Подтвердить что ты не робот

Простые URL-адреса в WCF Rest 4.0 без конечной косой черты

У меня есть проект WCF REST 4.0, основанный на шаблоне 40 службы сервиса REST WCF (CS). Я бы хотел показать простые URL-адреса конечных точек без привязки косых черт. Например:

Я просматриваю вышеуказанные URL-адреса как запросы ресурсов (не каталоги), поэтому я не думаю, что конечные косые черты здесь подходят.

К сожалению, я не могу получить поведение, которое я хочу, потому что меня всегда перенаправляют на/cars/and/trucks/с завершающей косой чертой.

Здесь, как я определил маршрут "машины" и метод обслуживания - обратите внимание, что я не включил ни одной косой черты в любом определении шаблона маршрута или URI:

// Global.asax.cs
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));

// CarService.cs
[WebGet(UriTemplate = "")]
public List<Car> GetCollection()
{
    return DataContext.GetAllCars();
}

Обратите внимание, что MVC не работает таким образом. С помощью метода MapRoute я могу направлять запросы непосредственно на http://www.domain.com/about без перенаправления на /about/. Как я могу получить такое же поведение в WCF REST 4.0?

4b9b3361

Ответ 1

Основная проблема, с которой вы столкнулись, заключается в том, что текущая версия WCF REST вызывает перенаправление 307 (к "/" ), когда у вас есть пустая строка для UriTemplate в вашем WebGet атрибут. Насколько мне известно, в текущей версии этого не происходит.

Тем не менее, существует пара решений "среднего уровня" для вашей проблемы, учитывая, что вы хотите решение, которое 1) позволяет дифференцировать службы, и 2) иметь (относительно) короткие URI.

Первое решение Вы можете поместить это в свой файл global.asax(за этот пример). Вы можете выполнить маршрут обслуживания для каждой службы:

RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));

На этом этапе вы можете заполнить свой UriTemplate в каждой службе:

[WebGet(UriTemplate = "all")]
CarPool GetAllCars();

[WebGet(UriTemplate = "{carName}")]
Car GetCar(string carName);

Это позволит вам URI:

www.domain.com/cars/all
www.domain.com/cars/123 or www.domain.com/cars/honda

аналогично для грузовиков:

www.domain.com/trucks/all
www.domain.com/trucks/123 or www.domain.com/trucks/ford

Второе решение Используйте хост службы из REST Starter Kit (т.е. WebServiceHost2Factory).

RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHost2Factory(), typeof(CarService)));

Это не приводит к перенаправлению 307 при использовании URI, которые вы пытаетесь использовать выше, и, таким образом, дает вам именно то, что вам нужно. Хотя я понимаю, что немного странно использовать этот хост службы factory, а не тот, который поставляется с WCF 4.

Ответ 2

Вам нужен UriTemplate, попробуйте что-то вроде этого:

 [ServiceContract()]
 public interface ICarService
 {

     [OperationContract]
     [WebGet(UriTemplate = "/Car")]
     CarPool GetAllCars();

     [OperationContract]
     [WebGet(UriTemplate = "/Car/{carName}")]
     Car GetCar(string carName);

 }

Ответ 3

Попробуйте поместить это в файл Global.asax.cs

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        string rawUrl = HttpContext.Current.Request.RawUrl.ToLower();

        if (rawUrl.EndsWith("/cars"))
        {
            HttpContext.Current.RewritePath(rawUrl + "/");  // append trailing slash
        }
    }

Ответ 4

Я имел дело с этой точной проблемой и просмотрел этот фрагмент в онлайн-документах MS:

По умолчанию маршрутизация не обрабатывает запросы, которые сопоставляются с существующим физическим файлом на веб-сервере. Например, запрос http://server/application/Products/Beverages/Coffee.aspx не обрабатывается маршрутизацией, если физический файл существует в Products/Beverages/Coffee.aspx. Маршрутизация не обрабатывает запрос, даже если он соответствует определенному шаблону, например {controller}/{action}/{id}.

Я понял, что мой шаблон маршрута соответствует каталогу, в котором была размещена моя служба. Похоже, что каталог обрабатывается так же, как физический файл, и шаблоны маршрутов, которые соответствуют каталогу, также игнорируются. Поэтому, следуя документации, я установил свойство RouteExistingFiles в значение "true" на RouteCollection. Моя служба теперь, кажется, правильно маршрутизирует запросы, и я смог сохранить синтаксис REST, который мне очень нравится.

Ответ 5

Более старый вопрос, но вот как я решил проблему с сервисом REST WCF4 (используя RouteTable в Global.asax для добавления ServiceRoutes). IIS7 настроен так, что к моменту запуска службы у меня есть пустой относительный путь, так что метод обработки UriTemplate пуст, как пример Will Car. Я использовал правило перезаписи в файле service.config службы, чтобы добавить "/", если это необходимо. Он всегда соответствует пути, затем проверяет исходный URI ({REQUEST_URI}), чтобы увидеть, содержит ли он путь без конечного "/".

    <rewrite>
        <rules>
            <!--
            This rule will append a "/" after "/car" if
            the client makes a request without a trailing "/".
            ASP however must have a trailing "/" to find
            the right handler.
            -->
            <rule name="FixCarPath" stopProcessing="true">
                <match url=".*" />
                <conditions>
                    <add input="{REQUEST_URI}" pattern="/car\?" />
                </conditions>
                <action type="Rewrite" url="{PATH_INFO}/" />
            </rule>
        </rules>
    </rewrite>

Ответ 6

Попробуйте изменить свой код в Global.asax из...

Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService))); RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));

... до...

WebServiceHostFactory factory = new WebServiceHostFactory();

Routes.Add(new ServiceRoute("cars", factory, typeof(CarService))); RouteTable.Routes.Add(new ServiceRoute("trucks", factory, typeof(TruckService)));

Ответ 7

Немного больше повторного использования:

public class Global : NinjectHttpApplication
{

    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();
        RegisterRoutes();
    }

    private void RegisterRoutes()
    {
        RouteTable.Routes.Add(new ServiceRoute("login", new NinjectWebServiceHostFactory(), typeof(LoginService)));
        RouteTable.Routes.Add(new ServiceRoute("incidents", new NinjectWebServiceHostFactory(), typeof(IncidentService)));
        SetRoutePrefixes();
    }
    //This is a workaround for WCF forcing you to end with "/" if you dont have a urlTemplate and redirecting if you dont have
    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        string rawUrl = HttpContext.Current.Request.RawUrl.ToLower();


        if (_routePrefixes.Any(rawUrl.EndsWith))
        {
            HttpContext.Current.RewritePath(rawUrl + "/");  // append trailing slash
        }
    }


    private static List<string> _routePrefixes; 
    private static void SetRoutePrefixes()
    {
        _routePrefixes = new List<string>();
        foreach (var route in RouteTable.Routes)
        {
            var r = route as Route;
            var routePrefix = r.Url.Split('/').First();
            _routePrefixes.Add(routePrefix);
        }
    }