Custom Post function to upload a file in Self Hosted REST API - vb.net

I have written a VB.Net Visual basic console application for Self hosting a custom file upload service to be consumed by an application. Concept being the end user uses the application to generate data, when completed the file is uploaded to our server without user intervention. I have complete control over both applications. The problem is I can't figure out the POST Upload signature that can accept several params, including the file or how to actually receive the file. The User application is in beta now, testing all other functionality excluding the "Send File" sub's. I've never seen a file larger then 180 KB; I plan on accepting files sizes up to 1 MB. This lets me place some limitations (and filters) to help avoid abuse of the service.
I'm using NuGet packages webapi.client (4.0.30506), webapi.selfhost (4.0.3056) (and their associated required packages) and newtonsoft.json (4.5.11) and PostMan to test/debug the process. I'm using Visual Studio 2019 (Fully patched and up to date). All of the examples and google research point only to C# (not my language of choice), or are for hosted solutions like IIS.
In Postman, the only place where filenames are accepted are in the body, form-data. So, there is where I set up my key/value pairs with matching (including case and order) the params as defined in the FileULRequest class.
Everything that I've tried returns either
'500 internal server error'
or
"Message": "No HTTP resource was found that matches the request URI 'http://10.0.1.102:21212/file/upload/'."
The class object of the request looks like this:
Public Class FileULRequest
Public Property EncToken As String 'Holds an encrypted token for authorization
Public Property Filename As String 'Holds a recommended file name
Public Property AppID As String 'Holds the client/app ID for simpler server actions
Public Property File As Byte() 'Not sure if this is the right type/ should be the encrypted file contents.
End Class
The POST function signature currently looks like this:
Imports System.Web.Http
Namespace Controllers
Public Class FileController
Inherits ApiController
Public Function PostUpload(<FromBody()> ByVal ObjRequest As FileULRequest) As String
Return ""
End Function
End Class
End Namespace
In the Sub Main I have: (note, this is cleaned out)
Sub Main()
API_URL = Dns.GetHostByName(Dns.GetHostName()).AddressList(0).ToString()
Dim ThisConfig As New HttpSelfHostConfiguration("HTTP://" & API_URL & ":" & API_PORT)
ThisConfig.Routes.MapHttpRoute(name:="FileUpload", routeTemplate:="{controller}/{ObjRequest}", defaults:=New With {.id = RouteParameter.Optional})
ThisConfig.MaxConcurrentRequests = API_MaxCon
Dim Config As HttpSelfHostConfiguration = ThisConfig
Using Webserver As New HttpSelfHostServer(Config)
Try
Webserver.OpenAsync().Wait() 'Start the web server
Console.WriteLine("Listening at: " & API_URL & ":" & API_PORT) 'use the URL & port defined
Console.WriteLine("Enter to end")
Catch ex As Exception
Console.WriteLine("Error:{0}", ex.Message.ToString)
Console.WriteLine("Enter to end")
Console.ReadLine()
End
End Try
Dim Cmd As String = UCase(Console.ReadLine())
End
End Using
End Sub
API_Port and API_MaxCon are properties stored in the Appsettings.
What I'm trying to do is set the FileULRequest object params, post this to the service, confirm & validate the data and, if successful, save the file onto a network share. I've tried a large number of different combinations and nothing seems to get close; I cant get inside the Post event in the debugger to figure out or test anything.

Related

twilio nuget package not sending SMS message in vb.net

Does the twilio asp.net helper library package NOT work in vb.net? I can get it to work in c# web app but not vb.net web app.
In a vb.net web application project the following code doesnt send an sms message and when stepping through with the debugger, errs on the send message line and brings up a file dialog asking for access to core.cs. The twilio library's were installed via nuget.
Public Shared Sub SendAuthCodeViaSms(ByVal number As String)
Dim twilioAccountInfo As Dictionary(Of String, String) = XmlParse.GetAccountInfoFromXmlFile("twilio")
Dim accountSid As String = twilioAccountInfo("username")
Dim authToken As String = twilioAccountInfo("password")
If (Not String.IsNullOrEmpty(accountSid) AndAlso Not String.IsNullOrEmpty(authToken)) Then
Dim client = New TwilioRestClient(accountSid, authToken)
client.SendMessage(TwilioSendNumber, ToNumber, "Testmessage from My Twilio number")
Else
'log error and alert developer
End If
End Sub
But in a C# web API project the same code sends the message as expected.
protected void Page_Load(object sender, EventArgs e)
{
const string AccountSid = "mysid";
const string AuthToken = "mytoken";
var twilio = new TwilioRestClient(AccountSid, AuthToken);
var message = twilio.SendMessage(TwilioSendNumber,ToNumber,"text message from twilio");
}
and all the sid's and tokens and phone number formats are correct, otherwise the c# one wouldnt send and I wouldnt get to the client.SendMessage part of vb.net version (client.SendSMSMessage produces the same result)
Twilio evangelist here.
I tried our your code by creating a simple VB console app and it worked for me.
The only thing I can think of is that either you are not getting your Twilio credentials correctly when parsing the XML, or the phone number you are passing into the function is not formatted correctly.
I'd suggest putting the result of call to SendMessage() into a variable and checking to see if RestException property is null:
Dim result = client.SendMessage(TwilioSendNumber, ToNumber, "Testmessage from My Twilio number")
If (Not IsNothing(result.RestException)) Then
' Something bad happened
Endif
If Twilio returns a status code greater than 400, then that will show up as an exception in the RestException property and will give you a clue as to whats going on.
If that does not work, you can always break out a tool like Fiddler to watch and see if the library is making the property HTTP request and Twilio is returning the proper result.
Hope that helps.

Can somebody give me an example of getting the content of a page from a URL in vb.net for windows 8?

I am very new to vb/.net and I'm trying to do something that I can do easily in classic vb. I want to get the source html for a webpage from the URL.
I'm using vb.net in Visual Studio Express for Windows 8.
I've read loads of stuff that talk about HttpWebRequest, but I can't get it to work properly.
I did at one point have it returning the html header, but I want to content of the page. Now, I can't even get it back to giving me the header. Ultimately, I want to process the html returned which I'll do (to begin with) the old-fashioned way and process the returned html as a string, but for now I'd like to just get the page.
The code I've got is:
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(New Uri(URL))
txtHTML.Text = request.GetRequestStreamAsync().ToString()
Can anyone help me with an example to get me going please?
You're trying to use an Async method in a synchronous way, which won't make any sense. If you're using .NET 4.5, you can try marking the calling method with Async and then using the Await keyword when calling GetRequestStreamAsync.
Public Sub MyDownloaderMethod()
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest
= System.Net.HttpWebRequest.Create(New Uri(URL))
' Use the Await keyword wait for the async task to complete.
Dim response = request.GetResponseAsync()
txtHTML.Text = response.GetResponseStream().ToString()
End Function
See the following MSDN article for more information on async programming with the Await keyword: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
Edit
You are receiving your error because you're trying to get the Request stream (what you send the server), and what you really want is the Response stream (what the server sends back to you). I've updated my code to get the WebResponse from your WebRequest and then retrieve the stream from that.
Public Shared Function GetWebPageString(ByVal address As Uri) As String
Using client As New Net.WebClient()
Return client.DownloadString(address)
End Using
End Function
There is also DownloadStringAsync if you don't want to block
request.GetRequestStreamAsync() is probably not a method. I think you're cribbing code from a site where someone wrote their own add-on methods to HttpWebRequest. Try request.GetResponse() to return a response object, then in the response object you can inspect the stream and convert it to text if you need to.
This worked for me in VB.Net 4.5
Public Async Sub GetHTML()
Dim PageHTML as string
Dim client As New HttpClient
Dim getStringTask As Task(Of String) = client.GetStringAsync(PageURL)
PageHTML = Await getStringTask
MsgBox(PageHTML)
End Sub

Execute a method on an existing process instance. Vb.Net

I have a windows service that I have been writing in Vb.Net. As part of this service it calls a class that has a long running Process.
I can execute commands to this process when I want to via the ServerCommands() class within the service, however I want to call these remotely. Possibly from a website or click once WPF application.
For this I have used a simple Tcp.Ip WCF example, and have verified it as working correctly.
This called OnStart()
Private _serverCommands As ServerCommands
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
Debugger.Launch()
' Action a new implementaion of the WCF Service on localhost
_host.AddServiceEndpoint(GetType(ICommunicationService), New NetTcpBinding(), String.Format("net.tcp://127.0.0.1:{0}", AppSettings.TcpServicePort))
_host.Open()
' Start the server command
_serverCommands = New ServerCommands()
_serverCommands.StartServer()
End Sub
However... when I'm calling the service through WCF its starting a new instance of the ServerCommands() Class rather than attaching to the already running thread.
The following call
Public Function DoWork() As String Implements ICommunicationService.DoWork
Dim command As String = "say hello world"
Dim service As IMinecraftService = New MinecraftService()
service.ExecuteServerSideCommand(command)
Return "Command Executed"
End Function
Implements this on the main service.
Public Sub ExecuteServerSideCommand(command As String) Implements IMinecraftService.ExecuteServerSideCommand
If (_serverCommands IsNot Nothing) Then
_serverCommands.SendCommand(command)
End If
End Sub
It appears that in debug _serverCommands is Nothing when it should be running.
How might I go about ensuring any command I execute through WCF communicates with the running instance instead of creating a new ServerCommand() instance??
I haven't tried WCF before, so I might be hitting a dead end... however I'm sure its possible.
Thanks in advance.
I found that I was calling a new instance of the MinecraftService each time I sent a command via WCF.
As Jeff rightly said, I was not making the object shared, I was only accessing a new instance of this class.
I changed it from
From
MyMainClass
Private _serverCommands As ServerCommands
My WcfService
Dim command As String = "say hello world"
MinecraftService.ServerCommands.SendCommand(command)
To
MyMainClass
Public Shared ServerCommands As ServerCommands
My WcfService
MinecraftService.ServerCommands.SendCommand(command)

How to change web service url dynamically

I have one web service reference in my project but it has two url one is live and second one is test,how to switch between these url dynamically in vb.net
http://api.test/test/SOAP.wsdl
http://api.live/live/SOAP.wsdl
'LOGPOINT:
Call mobjLogWrite.prWriteLogEntry(clsLogWriter.enuLogEntryType.INFORMATION, ASSEMBLY_ID, "Start fnHOTELSPROSearchExecute()", "fnHOTELSPROSearchExecute")
Dim objsoap As New b2bHotelSOAPService()
Dim getres As New getAvailableHotelResponse()
QLSearchXML = xmlData
objsoap.Timeout = 20000
objsoap.Url = "http://api.live/live/SOAP.wsdl"
'objsoap.Timeout = TIMEOUT
getres = objsoap.getAvailableHotel(HOTELSPRO_APIKEY.Trim(), strDestinationId, dtmCheckIn, dtmCheckOut, strCurrencyCode, "UK", True, fngetpax(xmlData), getfilter())
Call mobjLogWrite.prWriteLogEntry(clsLogWriter.enuLogEntryType.INFORMATION, ASSEMBLY_ID, "Start DeSerializing the XML Output", "fnHOTELSPROSearchExecute")
lHOTELSPROReturn = fnCustomSerializeObject(GetType(getAvailableHotelResponse), getres)
Call mobjLogWrite.prWriteLogEntry(clsLogWriter.enuLogEntryType.INFORMATION, ASSEMBLY_ID, "End DeSerializing the XML Output", "fnHOTELSPROSearchExecute")
lTempDOM.LoadXml(lHOTELSPROReturn)
Return lTempDOM
Catch ex As Exception
Call mobjLogWrite.prWriteLogEntry(clsLogWriter.enuLogEntryType.ERROR, ASSEMBLY_ID, "Catch Block Error:" + ex.ToString(), "fnCreateHOTELSPROSearchRequest")
Finally
'LOGPOINT:
Call mobjLogWrite.prWriteLogEntry(clsLogWriter.enuLogEntryType.INFORMATION, ASSEMBLY_ID, "Response From HotelsPro--->" & lHOTELSPROReturn, "fnHOTELSPROSearchExecute")
Call mobjLogWrite.prWriteLogEntry(clsLogWriter.enuLogEntryType.INFORMATION, ASSEMBLY_ID, "END Finally Block fnHOTELSPROSearchExecute()", "fnHOTELSPROSearchExecute")
End Try
the error response is returned
"I have one web service reference in my project but it has two url one is live and second one is test,how to switch between these url dynamically in vb.net"
Dynamically based on what, exactly?
Assuming you mean based on where the app is running, i.e. Test or Live, how about:
EDIT : Just saw it was meant to be in VB.Net
Dim MyService as String
If HttpContext.Current.Server.MachineName.ToString() = "LIVESERVER" Then
MyService = "http://api.live/live/SOAP.wsdl"
Else
MyService = "http://api.live/test/SOAP.wsdl"
End If
And change
objsoap.Url = "http://api.live/live/SOAP.wsdl"
to
objsoap.Url = MyService
If your Webservice is set to Dynamic, the URL is store in the app.config settings. To make this easier to change at run time (the app.config is readonly unless run with admin privileges), go to the project Settings and change the webservice setting from application scope to user scope.
Now you can change the webservice URL at any time in code using the my.settings.yourwebserviceurl... = "newwebserviceurl"
Next time you call the webservice, it will be from the new location. However, you will need to ensure both webservice call contain an indentical, or at least compatible webservice.

How can I write to my own app.config using a strongly typed object?

The following code has two flaws, I can't figure out if they are bugs or by design. From what I have seen it should be possible to write back to the app.config file using the Configuration.Save and according to http://www.codeproject.com/KB/cs/SystemConfiguration.aspx the code should work.
The bugs are shown in the source below and appear when you try to set the property or save the config back out.
Imports System.Configuration
Public Class ConfigTest
Inherits ConfigurationSection
<ConfigurationProperty("JunkProperty", IsRequired:=True)> _
Public Property JunkProperty() As String
Get
Return CStr(Me("JunkProperty"))
End Get
Set(ByVal value As String)
' *** Bug 1, exception ConfigurationErrorsException with message "The configuration is read only." thrown on the following line.
Me("JunkProperty") = value
End Set
End Property
Public Sub Save()
Dim ConfigManager As Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
' The add / remove is according to http://www.codeproject.com/KB/cs/SystemConfiguration.aspx
ConfigManager.Sections.Remove("ConfigTest")
' *** Bug 2, exception InvalidOperationException thrown with message "Cannot add a ConfigurationSection that already belongs to the Configuration."
ConfigManager.Sections.Add("ConfigTest", Me)
ConfigManager.Save(ConfigurationSaveMode.Full, True)
End Sub
Public Shared Sub Main()
Dim AppConfig As ConfigTest = TryCast(ConfigurationManager.GetSection("ConfigTest"), ConfigTest)
AppConfig.JunkProperty = "Some test data"
AppConfig.Save()
End Sub
' App.Config should be:
' <?xml version="1.0" encoding="utf-8" ?>
'<configuration>
' <configSections>
' <section name="ConfigTest" type="ConsoleApp.ConfigTest, ConsoleApp" />
' </configSections>
' <ConfigTest JunkProperty="" />
'</configuration>
End Class
I'd like to do it this way so that on the first run of the app I check for the properties and then tell the user to run as admin if they need to be set, where the UI would help them with the settings. I've already 'run as admin' to no effect.
Your code doesn't really make any sense. I took your example code and turned it into a simple example that works. Please note this is not best practise code, merely an example to aid you on your journey of learning the configuration API.
Public Class ConfigTest
Inherits ConfigurationSection
<ConfigurationProperty("JunkProperty", IsRequired:=True)> _
Public Property JunkProperty() As String
Get
Return CStr(Me("JunkProperty"))
End Get
Set(ByVal value As String)
' *** Bug 1, exception ConfigurationErrorsException with message "The configuration is read only." thrown on the following line.
Me("JunkProperty") = value
End Set
End Property
Public Overrides Function IsReadOnly() As Boolean
Return False
End Function
Public Shared Sub Main()
Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
Dim AppConfig As ConfigTest = config.GetSection("ConfigTest")
AppConfig.JunkProperty = "Some test data"
config.Save()
End Sub
End Class
This code will open the config file, modify the attribute JunkProperty and persist it back it the executable's configuration file. Hopefully this will get you started- it looks like you need to read about the configuration API a bit more.
I've used the API to create configuration sections for large scale enterprise apps, with several 1000 of lines of custom hierarchical config (my config was readonly though). The configuration API is very powerful once you've learnt it. One way I found out more about its capabilities was to use Reflector to see how the .NET framework uses the API internally.
Maybe you don't know Portuguese or c# but this is you want http://www.linhadecodigo.com.br/Artigo.aspx?id=1613
using BuildProvider from asp.net
After loading a configuration it is readonly by default, principally because you have not overriden the IsReadOnly property. Try to override it.
¿Is there something that prevents you from using a setting?
Looks like it is not possible by design. App.config is normally protected as it resides along with the app in the Program Files directory so must be amended at installation time by the installer.
Pity really, I'd like the app to have settings that an admin can set.
Sorry if I didn't understand your case, but yes, you can change App.config at runtime.
Actually, you will need to change YourApp.exe.config, because once your app is compiled, App.config contents are copied into YourApp.exe.config and your application never looks back at App.config.
So here's what I do (C# code - sorry, I still haven't learnt VB.Net)
public void UpdateAppSettings(string key, string value)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
foreach (XmlElement item in xmlDoc.DocumentElement)
{
foreach (XmlNode node in item.ChildNodes)
{
if (node.Name == key)
{
node.Attributes[0].Value = value;
break;
}
}
}
using (StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile))
{
xmlDoc.Save(sw);
}