Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Recently I worked on a plug-in based system, and one of the approaches of this system was to allow each plug-in (dll) to have the capability to host web services. I had never heard about such task before, I made a search on the Web and didn't find anything about that, so I decided to think and fortunately I came with a pretty good solution.

The HTTP Handler for .asmx

The first thing I did was to open the Web.Config file located in %windir%\Microsoft.NET\Framework\v2.0.50727\CONFIG and look at the following entry inside <httpHandlers>:

<add path="*.asmx" verb="*" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="False" />

Using Reflector, I found that the WebServiceHandlerFactory builds and returns an IHttpHandler in the GetHandler of the IHttpHandlerFactory interface, that was all I needed to know.

Creating the WebServiceBase class

So here it is what I did:

I created a new Class Library project and in this project, a class named WebServiceBase, this class could be anywhere, since it's an abstract class that will be the base class for the web services. The definition of this class is below:

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Reflection

Public MustInherit Class WebServiceBase
    Inherits WebService
    Implements IHttpHandlerFactory
    
    Private Shared wshf As New WebServiceHandlerFactory
    Private Shared coreGetHandlerMethod As MethodInfo = GetType(WebServiceHandlerFactory).GetMethod("CoreGetHandler", _
    BindingFlags.Instance Or BindingFlags.NonPublic)

    Public Function GetHandler(ByVal context As System.Web.HttpContext, ByVal requestType As String, ByVal url As String, _
    ByVal pathTranslated As String) As System.Web.IHttpHandler Implements System.Web.IHttpHandlerFactory.GetHandler
        Return DirectCast(coreGetHandlerMethod.Invoke(wshf, New Object() {Me.GetType, context, context.Request, context.Response}), IHttpHandler)
    End Function

    Public Sub ReleaseHandler(ByVal handler As System.Web.IHttpHandler) Implements System.Web.IHttpHandlerFactory.ReleaseHandler

    End Sub

End Class

Note the Reflection hack to call the CoreGetHandler method from WebServiceHandlerFactory, this is needed because this method is declared as Friend, and this method is the one that actually creates the IHttpHandler instance.

It's almost done! All you have to do now is create the web services, which will be classes that inherit from this one, so here is an example:

Imports System.Web.Services

<WebService(Namespace:="http://tempuri2.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
Public Class WSTest
    Inherits WebServiceBase

    <WebMethod()> _
    Public Function HelloWorld() As String
        Return "Hello World"
    End Function
End Class

Remember that everything above is in a Class Library, so compile this project, create a new web site and add this project as a reference.

This Class Library project I called WSLibrary, and as the WSTest is nothing more than a HttpHandler, you should add a new entry to your web.config for each Web Service you created, in this example above, I added:

<httpHandlers>
  <add path="WSTest.asmx" verb="*" type="WSLibrary.WSTest" validate="false"/>
</httpHandlers>

Now, every time a request to WSTest.asmx is made, it will be handled by the WSLibrary project. It can be changed very easily to suit your needs.

Conclusion

This approach worked very well for the project I was working on. I'm sure there are more things that could be made to make it even better, like you can make a way that only one entry in the httpHandlers is necessary for as many web services as you have.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionIn IIS7
evolvement
6:33 17 Mar '09  
Great post, I register the class in IIS6 like your post, IIS6 no any problem,
but IIS7 not work.
Please help me.

Thanks.
GeneralASP.NET AJAX
eeyrcr
7:44 20 Jan '09  
Hi,

Great post - but did you ever get it working with ASP.NET AJAX?

I really would love to get this working in my project - any updates / pointers?

Thanks,
- Chris
GeneralRe: ASP.NET AJAX
Bruno Piovan
10:26 3 Mar '09  
Hi Chris,
please, have a look at the posts with title "Can we use it in ASP .NET AJAX ?"

thanks!
GeneralWhy the need of Reflection Hack?
PJonDevelopment
13:24 5 Nov '08  
Hi, Bruno.

I was analysing your code but I didn't see the need for the Reflection Hack you used.

The GetHandler method of the WebServiceHandlerFactory simply calls the CoreGetHandler after raising the tracing enter event and making sure that the AspNetHostingPermission is satisfied.

After calling the CoreGetHandler it raises the tracing leave envent and returns the handler.

Your code bypass the security issue, as well the tracing events.

I just want to know why exactly you did that.

Regards,

Paulo Santos
http://pjondevelopment.50webs.com
GeneralRe: Why the need of Reflection Hack?
Bruno Piovan
0:01 6 Nov '08  
Hi Paulo,
I'm not sure if I understood your question, so I think I should ask why you don't think the reflection hack is needed.

thanks!
Bruno
GeneralRe: Why the need of Reflection Hack?
PJonDevelopment
8:49 6 Nov '08  
Hi Bruno,

The public GetHandler method does the following:

Public Function GetHandler(ByVal context As HttpContext, _
ByVal verb As String, _
ByVal url As String, _
ByVal filePath As String) As IHttpHandler

Dim caller As TraceMethod = _
IIf(Tracing.On, New TraceMethod(Me, "GetHandler", New Object() {}), Nothing)

If Tracing.On Then Tracing.Enter("IHttpHandlerFactory.GetHandler", caller, Tracing.Details(context.Request))
End If
New AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal).Demand

Dim compiledType As Type = WebServiceParser.GetCompiledType(url, context)

Dim handler As IHttpHandler = _
Me.CoreGetHandler(compiledType, context, context.Request, context.Response)

If Tracing.On Then Tracing.Exit("IHttpHandlerFactory.GetHandler", caller)
End If
Return handler
End Function

That's why I don't think the Reflection Hack is needed.
GeneralRe: Why the need of Reflection Hack?
thearcaner2
9:49 3 Mar '09  
Dim compiledType As Type = WebServiceParser.GetCompiledType(url, context) will not work. Thats why.
GeneralCan you give me a whole example?
JLKEngine008
21:10 25 Jun '08  
according to your description, Can you give me a whole example?
e-mai: hy2001al@163.com
thanks very much
QuestionCan we use it in ASP .NET AJAX ?
satriya
0:10 18 Feb '08  
Bruno, great article ! Solve my problem. But I always got an error when using it inside ASP .NET AJAX framework.

This my simple code :

protected void Page_Load(object sender, EventArgs e) {

ScriptManager sm = ScriptManager.GetCurrent(this.Page);

ServiceReference sf = new ServiceReference();
sf.Path = "WSTest.asmx";
sm.References.Add(sf);

ScriptReference sc = new ScriptReference();
sc.Path = "Demo.js";
sm.Scripts.Add(sc);

}

This is my Demo.js code :

function Test() {
WSLibrary.WSTest.HelloWorld(OnCompleted);
}

function OnCompleted(result) {
document.getElementById("message").innerHTML = result;
}

if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

I can't use WSTest.asmx reference from code above. But if i use it by right clicking and choose Web References, then everything goes fine.

Or maybe I missed something ?
GeneralRe: Can we use it in ASP .NET AJAX ?
Bruno Piovan
9:16 18 Feb '08  
Hello Satriya,
a quick workaround for this issue is to instead of adding a new httpHandler like

<httpHandlers>
<add path="WSTest.asmx" verb="*" type="WSLibrary.WSTest" validate="false"/>
</httpHandlers>

to web.config, create a plain .asmx file in your web project with the content:

<%@ WebService Class="WSLibrary.WSTest" %>


Let me know if it works for you.

Bruno
GeneralRe: Can we use it in ASP .NET AJAX ?
gkelly
20:01 25 Feb '08  
Bruno,

This info you have provided has been helpful for me, thank you. I have a large ajax type asp.net application that uses both aspx and asmx.
I have used the web deployment project from some time now and I really don't like it. So, I got rid of it and now place all the "codebehind" code in a separate assembly. I was using the method you mentioned to Satriya by creating basically a stub asmx file which would then point to the appropriate class. But, I wanted to get rid of those stub files for asmx. I already did for aspx, but the asmx's were a little more tricky. Anyway, I had to change one thing. btw, I use c#

Your code (in c#)

private WebServiceHandlerFactory _wshf = new WebServiceHandlerFactory();
private MethodInfo _coreGetHandlerMethod = typeof(WebServiceHandlerFactory).GetMethod("CoreGetHandler",
(BindingFlags)((int)BindingFlags.NonPublic + (int)BindingFlags.Instance));

IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string url, string pathTranslated) {
try {
return _coreGetHandlerMethod.Invoke(_wshf,
new object[] { this.GetType(), this.context, this.context.Request, this.context.Response }) as IHttpHandler;
}
}

I needed to change this to:

IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string url, string pathTranslated) {
try {
return _coreGetHandlerMethod.Invoke(_wshf,
new object[] { this.GetType(), context, context.Request, context.Response }) as IHttpHandler;
}
}

in other words, use the 'context' variable that was passed rather than the one in 'this'

This cleared up all the problem and everything works great. I'm not sure why the two would be different. Any insight there would be interesting.

gkelly
GeneralRe: Can we use it in ASP .NET AJAX ?
Bruno Piovan
3:51 26 Feb '08  
Hi gkelly,
thanks for the info!

When you're using asp.net ajax, the handler for .asmx is another one, that's why the code doesn't work properly.

this other handler generates some additional javascript code and that's the reason to use the new handler I believe, I tried to use that new handler instead of WebServiceHandlerFactory and unfortunatelly it was again not working properly because it checks if the .asmx file exists.

I'll try to make a good fix for this in some days when I get some free time.

Does asp.net ajax work ok with your code? In my VB code I'm not using "this" that is "me" in VB, so I could say that my code is the same as your second one, but I didn't use the try block, which shouldn't be necessary but I understand why you're using this.

I hope to end up with a good solution. Big Grin

Thanks again!
Bruno
GeneralRe: Can we use it in ASP .NET AJAX ?
gkelly
18:35 26 Feb '08  
Bruno,

By the time I heard of microsoft's ajax library, I had already written an ajax engine and based all of our code on it. So, I really don't know how they compare. I really love programming ajax type apps along with c# even though calling it 'ajax' is weird since I didn't initially know it by that term. javascript is a really cool language and C# is awesome. I really don't prefer VB, but if you come from a VB background, I can see why it would be nice. I come from a C++ background. I don't know if this answered your question, oh well.
GeneralRe: Can we use it in ASP .NET AJAX ?
Bruno Piovan
3:00 27 Feb '08  
Hi gkelly,
actually I just asked if asp.net ajax worked on your code with the try catch block Smile Because it requests some additional js from the web service, and as the handler beeing used doesn't do that, it throws the exception.

Try to create a simple web service in a web app project and request for file.asmx/jsdebug and you'll see what I mean, then try to do the same request for your ws in the class library.

Bruno
Newshow to use the Service??
JLKEngine008
21:10 25 Jun '08  
according to your description, Can you give me a whole example?
e-mai: hy2001al@163.com
thanks very much
GeneralRe: Can we use it in ASP .NET AJAX ?
Unagii
6:07 12 Jun '09  
Hello,

Did you manage to find a working solution about this asp.et ajax implementation ?!

Thanks again for your code sample.

Regards.

Seb
GeneralYou solved my problem.
Ashaman
3:17 27 Nov '07  
I figured there HAD to be a way to do this, but I couldn't find any examples online.
I had finally decided to start researching the way you have, but was not looking forward to it.

Thanks so much for publishing this great information.

You got my '5'.
GeneralRe: You solved my problem.
Bruno Piovan
13:24 27 Nov '07  
Hi Ashaman,
Thank you! Big Grin
GeneralGreat Idea
merlin981
5:30 26 Nov '07  
And very simple to implement.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Rhabot - World of Warcraft Bot
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GeneralRe: Great Idea
Bruno Piovan
6:02 26 Nov '07  
Thank you! Smile


Last Updated 29 Nov 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010