Я наткнулся на этот вопрос, пытаясь найти ответ сам, и так как я нашел способ сделать это, я решил ответить на него.
Причина, по которой я нуждался в этом, заключается в том, что я преобразовываю старый веб-сайт ASP.NET в ASP.NET MVC, и для целей совместимости мне нужен веб-сервис, доступный по определенному URL-адресу. Однако путь к этому URL-адресу теперь обрабатывается контроллером на новом сайте, поэтому я не могу иметь физический каталог с тем же именем (так как это предотвратит вызов контроллера для других URL-адресов с этим путем, отличным от веб-службы). ).
PageRouteHandler
, который используется RouteCollection.MapPageRoute
, действительно требует, чтобы обработчик целевого пути был производным от System.Web.Page
, что не относится к веб-службам. Поэтому вместо этого необходимо создать собственный обработчик страницы:
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));
}
}
Этот обработчик маршрута создаст соответствующий обработчик для веб-службы на основе запроса и сопоставленного виртуального пути службы.
Теперь вы можете добавить маршрут для веб-службы следующим образом:
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");
Надеюсь, это кому-нибудь поможет, несмотря на возраст этого вопроса. :)