Пользовательская маршрутизация в службах данных WCF - PullRequest
4 голосов
/ 09 декабря 2011

Мне нужно создать собственный маршрут для службы данных WCF, которая содержит сегмент, который необходимо извлечь для использования при фильтрации данных.

Пример:

http://mysample.net/mysamplesvc/client123/Users

Мне нужно извлечь client123 из маршрута. Похоже, класс Route может обеспечить нечто подобное, но я не уверен, как реализовать IRouteHandler для службы данных.

Это правильный путь? Есть хорошие примеры вокруг?

ТИА!

UPDATE:

Мне удалось найти решение, которое мне было нужно, с помощью некоторой пользовательской перезаписи URL в IDispatchMessageInspector. Приведенный ниже код - это мой первоначальный взлом, и мне нужно много чего почистить. но, похоже, работает. Если кто-нибудь видит что-то не так, пожалуйста, дайте мне знать.

    public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        HttpRequestMessageProperty httpmsg = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
        ...Additional logic for handling Query formats in OData


        UriTemplate template = new UriTemplate("mysamplesvc/{ClientId}", true);

        Uri prefix = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority));
        Uri uri = new Uri(HttpContext.Current.Request.Url.AbsoluteUri);
        UriTemplateMatch results = template.Match(prefix, uri);

        if (results != null && !string.IsNullOrEmpty(results.BoundVariables["ClientId"]))
        {
            _clientId = results.BoundVariables["clientId"].ToString();
        }

        if (!string.IsNullOrEmpty(_clientId))
        {
            httpmsg.Headers.Add("ClientId", _clientId);
            rewriteRequest();
        }
        return null;
    }

    private void rewriteRequest()
    {
        if (HttpContext.Current != null && HttpContext.Current.Session != null)
        {
            if (WebOperationContext.Current.IncomingRequest.UriTemplateMatch != null)
            {
                Uri serviceUri = HttpContext.Current.Session["ServiceUri"] as Uri;
                Uri requestUri = null;

                UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;

                if (serviceUri == null)
                {
                    UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri);

                    serviceUri = serviceUriBuilder.Uri;
                    HttpContext.Current.Session["ServiceUri"] = serviceUri;
                }

                if (serviceUri != null)
                {
                    OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = serviceUri;

                    UriBuilder requestUriBuilder = new UriBuilder(match.RequestUri);
                    string path = string.Empty;
                    if (match.RelativePathSegments[0] == _clientId)
                    {
                        foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
                        {
                            if (seg.Index != 0)
                            {
                                path += "/";
                                path += seg.Value;
                            }
                        }
                    }
                    else
                    {
                        foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
                        {
                            path += "/";
                            path += seg.Value;
                        }
                    }

                    UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri + path);

                    // because we have overwritten the Root URI, we need to make sure the request URI shares the same host
                    // (sometimes we have request URI resolving to a different host, if there are firewall re-directs
                    serviceUriBuilder.Host = serviceUri.Host;

                    requestUri = serviceUriBuilder.Uri;
                    OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = requestUri;
                    OperationContext.Current.IncomingMessageProperties["Via"] = requestUri;
                }
            }

        }
    }

Спасибо всем!

Ответы [ 2 ]

4 голосов
/ 12 декабря 2011

Другой вариант - использовать IncomingWebRequestContext , полученный из WebOperationContext . IncomingRequest .Это позволит вам напрямую получить доступ к URI.Недостатком является то, что вам придется анализировать с Uri.Segments, а затем вам нужно будет привязать другой фрагмент кода к формату uri.

Ваша проблема в конечном итоге связана с тем, что WCF, несмотря на все свои претензии, не поддерживает REST.REST должен быть набором операций, выполняемых над ресурсом, идентифицированным URI.Вместо этого WCF предоставляет «статическую» конечную точку и набор методов, более похожих на old-skool XML / SOAP, чем на настоящий REST.

Я лично обнаружил, что WCF очень проблематичен при работе со службами REST, которые работают с URI / ресурсом.Честно говоря, это мало что дало и только мешало.Существует множество архитектур REST, многие страдают от этого ограничения.Возможно, вы решите воспользоваться поддержкой WCF и найти библиотеку сериализации полезной нагрузки, которая поддерживает форматы, которые вы хотите предоставить.

Моим любимым на данный момент является protobuf-csharp-port , который поддерживает XML, JSON, протокол буфера и сообщения в кодировке URI.Существует краткое введение в создание службы REST с использованием protobuf-csharp-port .Хотя этот пример также является конечной точкой службы, а не основанным на ресурсах REST, базовый шаблон сериализации - это именно то, что вам нужно.

0 голосов
/ 12 декабря 2011

Я предполагаю, что это проект MVC

типичные маршруты в MVC, я полагаю, работают так:

//url looks like /controller/Details/42
public ViewResult Details(int id) {
  //do something
}

Вы можете добавить пользовательские маршруты следующим образом:

routes.MapRoute(
           "my special little route", // Route name
           "customer/{Cid}/programs/{Pid}",
           new { controller = "customer", action = "Details" }
       );

таким образом, вид будет выглядеть так:

//url looks like /customer/{21}/programs/42
public ViewResult Details(int Cid, int Pid) {
  //do something
}

так что теоретически вы должны быть в состоянии сделать это с вашей службой WCF. Если я не совсем понимаю, что вы говорите, и я с радостью постараюсь обновить свой ответ

...