簡體   English   中英

使用ASP.NET MVC中的路由映射到ASMX服務

[英]Mapping to an ASMX service using routing in ASP.NET MVC

我想知道是否有任何方法可以將URL映射到ASMX服務,就像處理頁面一樣(使用routes.MapPageRoute()方法)。

當我嘗試簡單地通過將MapPageRoute指向我的服務來執行此操作時,出現錯誤

類型'MvcApplication1.Services.EchoService'不繼承自'System.Web.UI.Page'。

馬蒂亞斯。

我偶然發現了這個問題,試圖自己找到答案,由於我確實找到了解決問題的方法,所以我想我會回答。

我之所以需要它,是因為我正在將一個舊的ASP.NET網站轉換為ASP.NET MVC,並且出於兼容性目的,我需要在特定URL上可用的Web服務。 但是,該URL的路徑現在由新站點中的Controller處理,因此我無法使用具有相同名稱的物理目錄(因為這將阻止針對該URL而不是Web服務的其他URL調用控制器。 )。

PageRouteHandlerPageRouteHandler使用的RouteCollection.MapPageRoute要求目標路徑的處理程序派生自System.Web.Page ,而Web服務並非如此。 因此,必須創建一個自定義頁面處理程序:

using System;
using System.Web;
using System.Web.Routing;
using System.Web.Services.Protocols;

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));
    }
}

該路由處理程序將基於請求和服務的映射虛擬路徑為Web服務創建適當的處理程序。

您現在可以為Web服務添加路由,如下所示:

routes.Add("RouteName", new Route("path/to/your/service", new RouteValueDictionary() { { "controller", null }, { "action", null } }, new ServiceRouteHandler("~/actualservice.asmx")));

注意:您必須在路由值字典中指定控制器和操作值(即使它們設置為null),否則Html.ActionLink幫助器將始終對每個單個鏈接使用此路由(除非在列表中找到匹配項)在此路線之前)。 由於您可能想在默認的MVC路由之前添加此路由,因此不要以這種方式進行匹配很重要。

當然,您可以創建自己的擴展方法來減輕此任務:

public static Route MapServiceRoute(this RouteCollection routes, string routeName, string url, string virtualPath)
{
    if( routes == null )
        throw new ArgumentNullException("routes");
    Route route = new Route(url, new RouteValueDictionary() { { "controller", null }, { "action", null } }, new ServiceRouteHandler(virtualPath));
    routes.Add(routeName, route);
    return route;
}

之后,您可以簡單地執行以下操作:

routes.MapServiceRoute("RouteName", "path/to/your/service", "~/actualservice.asmx");

我希望這可以幫助某人,盡管這個問題已經存在了很長時間。 :)

現在,我們已經花了兩年的時間,如何使用Web API呢? :)

編輯:開玩笑,如果那對您不起作用,您仍然需要一個答案,請發表評論,我將看看是否無法提出更好的建議。

我嘗試了原始帖子的解決方案( 也在此處發布 ),但是遇到了一個嚴重的問題。 我無法在Web服務中定位Web方法。 嘗試這樣做時,出現異常,指出文件不存在。

如果您確實希望將MVC路由映射到.ASMX Web服務,請在此處說明解決方案。

我認為該解決方案通過濫用內置類型來解決問題,因為它使用反射繞過內置.NET類型的有意限制性訪問成員。

這是我采用的方法,我相信它會更簡單。

  1. 首先,您應該在.ASMX文件中設計Web服務,以便所有Web服務都充當已發布的界面。 那時我們不需要直接針對.ASMX Web服務的方法。 重要的代碼已在與應用程序的入口點無關的核心類中重新使用。 無論如何,我們都需要這樣做,以便我們可以運行自動化測試!

  2. 用具有自定義路由處理程序和http處理程序的新路由替換MVC的Web服務方法。

舊路線:

        routes.MapRoute(
            "Lead",
            "lead/{action}.mvc",
            new { controller = "Lead" });

新路線:

        var dict = new RouteValueDictionary
                   {
                       { "controller", null },
                       { "action", null }
                   };
        var handler = new LeadRouteHandler();
        var route = new Route("lead/MVC_General.mvc", dict, handler);
        routes.Add("Lead", route);

請注意,新路由的動作已硬編碼為“ MVC_General”。 這是因為我希望改進巨型控制器類,並為每個操作創建一個處理程序,這樣我就可以擁有一個小型類,並對每個Web方法負責。

  1. 實現路線的處理程序。

IRouteHandler:

public class LeadRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new LeadHttpHandler();
    }
}

IHttpHandler:

public class LeadHttpHandler : IHttpHandler
{

    public bool IsReusable
    {
        get { return false; }
    }

    public void ProcessRequest(HttpContext context)
    {
        // Just enough code to preserve the route's json interface for tests
        var typedResult = new PsaLeadSubmissionResult();
        typedResult.Registered = false;
        typedResult.Message = new List<string>
                              {
                                  "Not Implemented"
                              };

        var jsonResult = JsonConvert.SerializeObject(typedResult);

        context.Response.Write(jsonResult);
    }
}

從IHttpHandler的ProcessRequest方法中,我們可以完全控制該路由的操作。 通過精心設計的Web服務體系結構,我們要做的就是調用支持您嘗試將路由映射到的.ASMX Web方法的類。

結果是一個非常干凈的Global.asax文件。 僅通過手動檢查URL,我們就可以在沒有URL路由的情況下完成所有這些工作,但這對文件來說實在是太重要了,以至於無法膨脹。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM