MapHttpRoute vs MapRoute for basic POST WebAPI - asp.net

Given the following simple Web API (not part of an MVC project, just an empty ASP.NET site) which I've taken from a tutorial:
Public Class AwesomeController
Inherits ApiController
Public Function [Get]() As String
Return "Hello. The time is " & DateTime.Now.ToString
End Function
Public Function Post(<FromBody> yourName As String) As String
Return String.Format("Hi {0}, you posted here at {1}", yourName, DateTime.Now.ToString)
End Function
End Class
I am creating the Route within global.asax like this:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
GlobalConfiguration.Configuration.Routes.Add("default", New HttpRoute("{controller}"))
End Sub
This works fine, but I've read that WebAPI Routing should preferably be created using MapHttpRoute so that the service can exist in isolation. Is this true?
If so, can anyone post the code to replace my global.asax version?
Update
I figured out the last bit, but would still appreciate knowing whether there is a 'correct' way?
RouteTable.Routes.MapHttpRoute("default", "{controller}")

The MapHttpRoute extension method is simply a convenient way to register HttpRoute instances in your routing table. It's perfectly okay to manually create and register an HttpRoute without making use of the shorthand method, though.
If you want to understand the inner workings of MapHttpRoute, take a look at the source code: HttpRouteCollectionExtensions.cs.

Related

How can I add Console dll file in web application?

By following the CHATGPT guidelines I added a Console file dll (Inboundnightlybatchfile is my console file) in the bin folder of my web application. To access the dll need to import in our application. So I write this using Inboundnightlybatchfile; But the dll file name does not appear in the IntelliSense, and it throws a compile time error.
I want to add the Console file dll to an Web application
Well, HOW do you share ANY code in your existing application, or code from "other" applications?
why of course you have/put that code in a class.
I mean in your project now, how do you use/enjoy a bunch of helper code and routines?
You wind up with a class, and then in code create a instance of that class.
So, say I have a class that holds some information about a hotel?
Then you add a class to your project, and then simple use that class in code.
So, say this class:
Public Class Hotel
Public HotelName As String
Public City As String
Public HotelDescripiton As String
Public FirstName As String
Public Lastname As String
Public ReadOnly Property FullName As String
Get
Return FirstName & " " & Lastname
End Get
End Property
End Class
Then in code, you can use that "code"
eg:
Dim OneHotel As New Hotel
OneHotel.HotelName = "Super 8 Hotel"
OneHotel.FirstName = "John"
OneHotel.Lastname = "Smith"
Debug.Print(OneHotel.FullName)
Output:
John Smith
Same goes for a console application. If you want share that code, then move the console code you want to share to a class.
Say I have this console application. When I run it, it will display all my drives on the computer.
So, from command prompt I have this:
So, now lets say I want to use above in my web site - to display/list all the hard drives.
So, the code for above console application is this:
Sub Main()
Dim cMyCode As New clsSharedCode
Dim sDriveList As List(Of String)
sDriveList = cMyCode.GetDrives
For Each s As String In sDriveList
Console.WriteLine(s)
Next
End Sub
But, the "working" code for that console been moved to a class called clsSharedCode.
That is this:
Imports System.IO
Public Class clsSharedCode
Public Function GetDrives() As List(Of String)
Dim DriveList As New List(Of String)
Dim allDrives As DriveInfo() = DriveInfo.GetDrives
For Each d As DriveInfo In allDrives
Dim s As String
s = $"Drive:{d.Name} Volume:{d.VolumeLabel} Type:{d.DriveType} Ready:{d.IsReady}"
DriveList.Add(s)
Next
Return DriveList
End Function
End Class
Ok, so now lets use above in our web site.
We simple set a reference to vbconsole.exe.
So, now this web page markup:
<h3>Drives on computer</h3>
<asp:ListBox ID="ListBox1" runat="server" Height="223px" Width="423px">
</asp:ListBox>
code behind
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim cConsoleCode As New VBConsole.clsSharedCode
Dim sDriveList As New List(Of String)
sDriveList = cConsoleCode.GetDrives
For Each sDrive As String In sDriveList
ListBox1.Items.Add(sDrive)
Next
End If
End Sub
And then we get this:
So, to "share" code? How this works EVEN with a simple plain jane console application is quite much the same as you "always" done this.
This does mean/suggest that the working code in your console application should be moved out to a shared code class that BOTH the console application, and now your web application can use and enjoy.
But, be a a web site, or even a simple console application?
The why and how of sharing the code quite much is the same in .net. You share code by using a object approach, and this is quite much the WHOLE foundation as to how .net code works - including that of sharing code between systems and applications.
So, in my web application, I simple set a reference to vbconsole.exe, and now I am free to use + consume any code in that console appliation. however, as noted, like you ALWAYS done to share code? You will as a general rule move that code out to a class, and then any other application is free to consume + use that code by using the public class code you have in that application. So, that MySharedCode class in the console application can now be used by any other .net application, include that asp.net web site.
so, .net is "primarily" a object based system, and this is the main pillar and foundation of how you re-use and share .net code. You share such code by creating class(s) with that code, so then your existing application (the console application) can use those class(s), and as above shows, by a simple reference to the vbconsole.exe application, the web site can also use + enjoy + consume that code also.
So, becasue a class forces you to seperate out the UI parts from the code parts, then even adopting this approach in a simple console application means that such code can be used + consumed by any type of application. you can write another console applcation, and reference our above console application and use that code.
but, we can also create a windows desktop program, and again reference the vbconsole.exe application. And so can our web based applcation.
And even MORE amazing? You can consume the above class in c#, or vb.net, and again it don't matter!

VB.Net: call sub from shared sub

I have some Ajax on a web page that feeds some data to a server-side VB.Net method. Once that data is in the server-side method, I need to call another server-side method to use the data I just collected. Here is a really simplified example:
' This method gets the input from the Ajax code on the web page.
<System.Web.Services.WebMethod> _
Public Shared Sub GetAwesome(VBInputText As String)
Dim strTest As String = VBInputText
' Now that we have collected input from the user,
' we need to run a method that does a ton of other stuff.
DisplayAwesome(VBInputText)
End Sub
Protected Sub DisplayAwesome(AwesomeIn As String)
' The real app does a lot more than this. For this example, it
' just sets the text of a literal.
litAwesomeResult.Text = AwesomeIn
End Sub
Of course, in the above example DisplayAwesome(VBInputText) gives me the 'Cannot refer to an instance member...' error. So, is it possible now to call Protected Sub DisplayAwesome from Public Shared Sub GetAwesome? I'm hoping to stay close to this sort of solution because it would play very well with the app as it is already written by another coworker.
unfortunately you cannot do this, Since the page method DisplayAwesome is defined as Protected and you requires an instance of the class to access the Protected method. But changes in another instance will not reflect in the current UI. another thing you can do is Make DisplayAwesome as Shared, but this time you cannot access the UI elements inside the shared function.
The thing you can do in this situation is, return data to the called method(in front end) and handle the litAwesomeResult.Text there
Call sub with name of Form Class like this:
FormName.DisplayAwesome(VBInputText)
In VB.Net, you can call the method not shared from a shared method with Name of Form Class by default instance, because The default instance is an object Form type that the VB application framework create and manage it, when the form is added to the project.
For more info see this :
VB.NET Default Form Instances

What type of variable could I use for this?

What I am trying to do is simple in principle, but the lifecycle of ASP.NET pages is throwing a bucket of cold water into my day.
Here is the problem
We have implemented URL Redirection and I've inherited code that reads like this in Global.ASAX, on Sub Application_BeginRequest:
dv.Table = CommonFunctions.ConvertXmlFileToDataSet("/XmlData/WebAppFolders.xml").Tables("Application")
dv.RowFilter = "'" + fullOrigionalPath + "' LIKE '%'+ folder + '%'"
If dv.Count > 0 Then 'match on key to redirect
If fullOrigionalPath.EndsWith(dv(0)("folder") + "/") Then
Context.RewritePath(dv(0)("basePage"), True)
Else 'missing page in directory --> redirect
HttpContext.Current.Items("Raise404") = "true"
Response.Redirect("/" + dv(0)("folder"))
End If
Return
End If
Basically we are reading a large XML file that contains the URL redirects. That's working fine. The problem happens in the line...
HttpContext.Current.Items("Raise404") = "true"
In the context of Application_BeginRequest, the session object is not yet available, so I could not use it to store a flag which I named Raise404. Instead I had to resort to using the Items collection.
The problem occurs when the redirect takes place. The new page lifecycle destroys the Items array and overwrites it with a new empty one.
By the time I try to use my flag Raise404, it no longer exists on my page PreRender event.
To complicate matters we use master pages, and so I was asked to place the code that we want to execute in the master page
Ideally, if the Items array wasn't being destroyed, this code would work:
Private Sub Page_PreRender(sender As Object, e As System.EventArgs) Handles Me.PreRender
If HttpContext.Current.Items("Raise404") IsNot Nothing AndAlso HttpContext.Current.Items("Raise404").Equals("true") Then
Response.StatusCode = 404
HttpContext.Current.Items("Raise404") = Nothing
End If
End Sub
I am not sure what kind of variable I could use to store my flag and allow it to survive the redirect.
Any ideas?
Update: The problem is that the HTTP Handler servicing my request is System.Web.DefaultHTTPHandler, which does not implement IRequiresSessionState, and so when my request is being handled inside Global ASAX there is no session created. So, it seems like the solution will be to write a custom HTTPHandler that implements IRequiresSessionState, and use that for all my .aspx files. Even then, a session state is not created in Global.ASAX until PreRequestHandlerExecute is raised. So, putting it all together I think I need to write a custom HTTP Handler that implements IRequiresSessionState, and delay the redirection of the page until PreRequestHandlerExecute is raised where I will be able to store my flag into the Session state, and only after that, redirect my page.
Not very elegant, and I wonder if there will be any performance implications.
Have you considered using the query string for that?
Response.Redirect("/" & dv(0)("folder") & "?Raise404=true")
Then, in your Master Page, simply check QueryString("Raise404") and act accordingly.
The only drawback I can see is that a malicious client could deliberately add Raise404=true to the query string, which is not possible with your current solution. However, I do not see how that could do any harm.
As I suspected, my problem was directly tied to the fact that IIS 8 will avoid using an HTTPHandler that implements IRequiresSessionState if for performance reasons it detects that a session object is not needed, and so because the redirect code was happening during the Application_BeginRequest event, IIS was handling up to that point my requests using System.Web.DefaultHTTPHandler.
So, upon further research, I found this which was tremendous help:
IRequiresSessionState - how do I use it?
And I also documented myself on this article:
http://forums.iis.net/t/1094546.aspx
What solved my problem was to write a dummy HTTPHandler class. I added a new class to my app_code folder:
Imports System.Web
Public Class HTTPRequestHandler : Implements IHttpHandler, IRequiresSessionState
Private OriginalHandler As IHttpHandler
Public Sub New(handler As IHttpHandler)
Me.OriginalHandler = handler
End Sub
Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
Throw New InvalidOperationException("HTTPRequestHandler cannot process requests.")
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
Public ReadOnly Property Handler() As IHttpHandler
Get
If Me.OriginalHandler IsNot Nothing Then
Return Me.OriginalHandler
End If
Return HttpContext.Current.Handler
End Get
End Property
End Class
Now, during Application_BeginRequest, session is not available but HttpContext.Current.Items is available. So, as the second article suggests, during PostMapRequestHandler I put a condition:
If HttpContext.Current.Items("Raise404") IsNot Nothing Then
Context.Handler = New MyNameSpace.HTTPRequestHandler(Context.Handler)
End If
And finally, that created the session object that I could finally use during PreRequestHandlerExecute:
HttpContext.Current.Session("Raise404") = "true"
Response.Redirect(HttpContext.Current.Items("Redirect"))
I will definitely not argue that this is not elegant, but it works and I can raise my 404 error during Page_PreRender on my master page.
I hope this may help others.
Cheers.

WCF Service not returning collection in web application

My WCF service is hosted on local IIS. I could not get the result from the wcf call when I call it from the application. But it is strange that it is showing correct result in debugging(while step into the service classes) and returning array of object in the staging classes. and when debugging comes to the application it returns empty array. I have below call from application.
public List<SurveyQuestion> GetCommonQuestionsForCompentency()
{
List<SurveyQuestion> questions = new List<SurveyQuestion>();
SurveyQuestion[] ques = null;
ICSSService.SurveyServiceClient client = null;
try
{
client = (SurveyServiceClient)WCFSecurityEntityForSurvey.getSurveyClient();
ques = client.GetCommonQuestionsByCategoryType(2);
questions = ques.ToList<SurveyQuestion>();
return questions;
}
catch (Exception)
{
throw;
}
finally{ client.Close();}
}
Call in the wcf service class shown below
Whats going wrong with the implementation. Any help?
EDIT :
It is working for a simple service call without list. I think the problem may be in the returning of collection. I found the similar questions Here. But did not get much from this.
I have similar problem with this.This is because References are not added correctly and I modified reference.cs file. So data is not gaining correctly if namespaces are different in the application. Just check the namespaces in your application. See if one of the class in your application have different namespace than others
All you need to do is add a completed function and then add the grid data source to that.
in the page load add
AddHandler client.GetEndorsementCompleted, AddressOf GetEndorsement
then add the following function to let the async function hit.
Private Sub GetEndorsement(ByVal sender As Object, ByVal e As
SR.GetEndorsementCompletedEventArgs)
If Not e.Result.Equals(Nothing) Then
'Data grid binding
End If
End Sub
In case of c# you can using this link from code project that demonstrate

Using IHttpModule Over Global.asax

I've been given the thrilling task of re-writing our exception handling system. Whilst I will state that handling exceptions from an application-wide point of view isn't something we want, typically it's unavoidable when our team are understaffed for the sheer amount of work we need to push out the door, so please, no flaming the globalised solution to exception handling here :)
I've had a good hunt to see what common solutions exist. At the moment we use Global.asax with the Application_Error event to do Server.GetLastError() which is placed in Session state then a redirect is called to another page where the session data is then retrieved and output in a human readable format. The redirect also calls a sproc which will carefully audit the error information which is a) e-mailed to the developers and b) viewed from a web page only viewable by developers.
The new way I've seen of doing things is using the IHttpModule interface using a class in App_Code to do something along these lines (this is my quick implementation)
Imports Microsoft.VisualBasic
Public Class ErrorModule : Implements IHttpModule
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
' Not used
End Sub
Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
AddHandler context.Error, AddressOf context_Error
End Sub
Public Sub context_Error(ByVal sender As Object, ByVal e As EventArgs)
Dim ex As Exception = HttpContext.Current.Server.GetLastError
' do something with the error
' call the stored procedure
' redirect the user to the error page
HttpContext.Current.Server.ClearError()
HttpContext.Current.Response.Redirect("index.htm")
End Sub
End Class
My question is, what is the benefit of this solution over using Global.asax events? Additionally, what is the best way to hand the data to an error page?
EDIT: The code above does work by the way ;)
EDIT: Also, how does the HttpModule work behind the scenes? Does it just register the Error event to that particular function on application start?
UPDATE:
Upon much further investigation it seems grabbing session data is really, really messy when it comes to using IHttpModule interface. I don't think MS have matured HttpModule enough for it to be used in our particular scenario - until there are events specific to session data it's too dangerous for us to use.
Using a module has the advantage of being easily removable, all you need to do to disable it is to remove it from <httpModules> in your config.
As far as your data goes, try going with Server.Transfer or Server.RewritePath - that will keep all the current data (including the last server error).
If for some reason it clears the last error, you can save the error to HttpContext.Items before the transfer/rewrite and then retrieve it afterwards.
Edit: In response to your edit, an IHttpModule attaches to any appropriate events in it's IHttpModule.Init implementation.
HttpModule basically does the same thing as Global.asax. It's designed as a more reusable and self-contained module for event handling.

Resources