Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASMX web services routing in ASP.NET Web Forms

NOTE: There is no MVC in this code. Pure old Web Forms and .asmx Web Service.

I have inherited a large scale ASP.NET Web Forms & Web Service (.asmx) application at my new company.

Due to some need I am trying to do URL Routing for all Web Forms, which I was successfully able to do.

Now for .asmx, routes.MapPageRoute does not work. Based on the below article, I created an IRouteHandler class. Here's how the code looks:

using System;
using System.Web;
using System.Web.Routing;
using System.Web.Services.Protocols;
using System.Collections.Generic;
public class ServiceRouteHandler : IRouteHandler
{
private readonly string _virtualPath;
private readonly WebServiceHandlerFactory _handlerFactory = new WebServiceHandlerFactory();

public ServiceRouteHandler(string virtualPath)
{
    if (virtualPath == null)
        throw new ArgumentNullException("virtualPath");
    if (!virtualPath.StartsWith("~/"))
        throw new ArgumentException("Virtual path must start with ~/", "virtualPath");
    _virtualPath = virtualPath;
}

public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    // Note: can't pass requestContext.HttpContext as the first parameter because that's
    // type HttpContextBase, while GetHandler wants HttpContext.
    return _handlerFactory.GetHandler(HttpContext.Current, requestContext.HttpContext.Request.HttpMethod, _virtualPath, requestContext.HttpContext.Server.MapPath(_virtualPath));
}

}

http://mikeoncode.blogspot.in/2014/09/aspnet-web-forms-routing-for-web.html

Now when I do routing via Global.asax, it work for the root documentation file but does not work with the Web Methods inside my .asmx files.

 routes.Add("myservice", new System.Web.Routing.Route("service/sDxcdfG3SC", new System.Web.Routing.RouteValueDictionary() { { "controller", null }, { "action", null } }, new ServiceRouteHandler("~/service/myoriginal.asmx")));

    routes.MapPageRoute("", "service/sDxcdfG3SC", "~/service/myoriginal.asmx");

Goal

I would like to map an .asmx Web Method URL such as www.website.com/service/myservice.asmx/fetchdata to a URL with obscured names in it like www.website.com/service/ldfdsfsdf/dsd3dfd3d using .NET Routing.

How can this be done?

like image 322
milan m Avatar asked Feb 02 '18 08:02

milan m


People also ask

How use Asmx webservice in asp net?

Step (1) : Select File -> New -> Web Site in Visual Studio, and then select ASP.NET Web Service. Step (2) : A web service file called Service. asmx and its code behind file, Service. cs is created in the App_Code directory of the project.

What is Asmx file web service?

ASMX provides the ability to build web services that send messages using the Simple Object Access Protocol (SOAP). SOAP is a platform-independent and language-independent protocol for building and accessing web services.

Is Asmx web service obsolete?

If you can work with WCF then yes the ASMX services are obsolete because the WCF can fully replace them with more performance and flexibility (multiple binding), functionality.

What is URL routing in asp net?

ASP.NET Routing Overview. URL routing allows you to configure an application to accept request URLs that do not map to physical files. A request URL is simply the URL a user enters into their browser to find a page on your web site.


1 Answers

It is slightly more tricky to do this with routing than in the article you posted because you don't want the incoming URL to have a query string parameter and it looks like the WebServiceHandler won't call the method without an ?op=Method parameter.

So, there are a few parts to this:

  1. A custom route (ServiceRoute) to do URL rewriting to add the ?op=Method parameter
  2. An IRouteHandler to wrap the WebServiceHandlerFactory that calls the web service.
  3. A set of extension methods to make registration easy.

ServiceRoute

public class ServiceRoute : Route
{
    public ServiceRoute(string url, string virtualPath, RouteValueDictionary defaults, RouteValueDictionary constraints)
        : base(url, defaults, constraints, new ServiceRouteHandler(virtualPath))
    {
        this.VirtualPath = virtualPath;
    }

    public string VirtualPath { get; private set; }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        // Run a test to see if the URL and constraints don't match
        // (will be null) and reject the request if they don't.
        if (base.GetRouteData(httpContext) == null)
            return null;

        // Use URL rewriting to fake the query string for the ASMX
        httpContext.RewritePath(this.VirtualPath);

        return base.GetRouteData(httpContext);
    }
}

ServiceHandler

public class ServiceRouteHandler : IRouteHandler
{
    private readonly string virtualPath;
    private readonly WebServiceHandlerFactory handlerFactory = new WebServiceHandlerFactory();

    public ServiceRouteHandler(string virtualPath)
    {
        if (virtualPath == null)
            throw new ArgumentNullException(nameof(virtualPath));
        if (!virtualPath.StartsWith("~/"))
            throw new ArgumentException("Virtual path must start with ~/", "virtualPath");
        this.virtualPath = virtualPath;
    }

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        // Strip the query string (if any) off of the file path
        string filePath = virtualPath;
        int qIndex = filePath.IndexOf('?');
        if (qIndex >= 0)
            filePath = filePath.Substring(0, qIndex);

        // Note: can't pass requestContext.HttpContext as the first 
        // parameter because that's type HttpContextBase, while 
        // GetHandler expects HttpContext.
        return handlerFactory.GetHandler(
            HttpContext.Current, 
            requestContext.HttpContext.Request.HttpMethod,
            virtualPath, 
            requestContext.HttpContext.Server.MapPath(filePath));
    }
}

RouteCollectionExtensions

public static class RouteCollectionExtensions
{
    public static void MapServiceRoutes(
        this RouteCollection routes,
        Dictionary<string, string> urlToVirtualPathMap,
        object defaults = null,
        object constraints = null)
    {
        foreach (var kvp in urlToVirtualPathMap)
            MapServiceRoute(routes, null, kvp.Key, kvp.Value, defaults, constraints);
    }

    public static Route MapServiceRoute(
        this RouteCollection routes, 
        string url, 
        string virtualPath, 
        object defaults = null, 
        object constraints = null)
    {
        return MapServiceRoute(routes, null, url, virtualPath, defaults, constraints);
    }

    public static Route MapServiceRoute(
        this RouteCollection routes, 
        string routeName, 
        string url, 
        string virtualPath, 
        object defaults = null, 
        object constraints = null)
    {
        if (routes == null)
            throw new ArgumentNullException("routes");

        Route route = new ServiceRoute(
            url: url,
            virtualPath: virtualPath,
            defaults: new RouteValueDictionary(defaults) { { "controller", null }, { "action", null } },
            constraints: new RouteValueDictionary(constraints)
        );
        routes.Add(routeName, route);
        return route;
    }
}

Usage

You can either use MapServiceRoute to add the routes one at a time (with an optional name):

public static class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        var settings = new FriendlyUrlSettings();
        settings.AutoRedirectMode = RedirectMode.Permanent;
        routes.EnableFriendlyUrls(settings);

        routes.MapServiceRoute("AddRoute", "service/ldfdsfsdf/dsd3dfd3d", "~/service/myoriginal.asmx?op=Add");
        routes.MapServiceRoute("SubtractRoute", "service/ldfdsfsdf/dsd3dfd3g", "~/service/myoriginal.asmx?op=Subtract");
        routes.MapServiceRoute("MultiplyRoute", "service/ldfdsfsdf/dsd3dfd3k", "~/service/myoriginal.asmx?op=Multiply");
        routes.MapServiceRoute("DivideRoute", "service/ldfdsfsdf/dsd3dfd3v", "~/service/myoriginal.asmx?op=Divide");
    }
}

Alternatively, you can call MapServiceRoutes to map a batch of your web service routes at once:

public static class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        var settings = new FriendlyUrlSettings();
        settings.AutoRedirectMode = RedirectMode.Permanent;
        routes.EnableFriendlyUrls(settings);

        routes.MapServiceRoutes(new Dictionary<string, string>
        {
            { "service/ldfdsfsdf/dsd3dfd3d", "~/service/myoriginal.asmx?op=Add" },
            { "service/ldfdsfsdf/dsd3dfd3g", "~/service/myoriginal.asmx?op=Subtract" },
            { "service/ldfdsfsdf/dsd3dfd3k", "~/service/myoriginal.asmx?op=Multiply" },
            { "service/ldfdsfsdf/dsd3dfd3v", "~/service/myoriginal.asmx?op=Divide" },
        });
    }
}

NOTE: If you were to have MVC in the application, you should generally register your MVC routes after these routes.

References:

  • Creating a route for a .asmx Web Service with ASP.NET routing
  • .NET 4 URL Routing for Web Services (asmx)
like image 96
NightOwl888 Avatar answered Oct 15 '22 17:10

NightOwl888