基于查询参数的WCF REST服务URL路由

时间:2015-06-01 11:44:05

标签: c# web-services wcf rest

由于WCF路由不支持REST服务的路由,因此我创建了一个REST服务,该服务有一个接受所有传入请求的enpoint,而不是根据查询参数重定向这些请求。
我是按照这篇文章http://blog.tonysneed.com/2012/04/24/roll-your-own-rest-ful-wcf-router/完成的。

此方法适用于传递请求并返回结果。问题是每当我从实际服务中得到错误(如404)时,返回给客户端的消息是400(错误请求)。
我想要的是一个路由代理,实际上只是根据查询将调用重定向到真实服务,并将所有错误返回给客户端,因为它们来自真实服务。

这是否是我尝试完成的正确方法,还是有更简单或更好的解决方案?

任何帮助表示赞赏!

在下面我添加了我的代码的样子 app.config:

<!--
  System.net
-->
<system.net>
<settings>
  <servicePointManager expect100Continue="false" useNagleAlgorithm="false" />
</settings>
<connectionManagement>
  <add address="*" maxconnection="24" />
</connectionManagement>
</system.net>

<!-- 
  System.ServiceModel 
-->
<system.serviceModel>

<!-- 
    Services 
-->
<services>
  <service name="RoutingGateway.RoutingService">
    <endpoint address="/api/routing" binding="webHttpBinding" bindingConfiguration="secureWebHttpBinding" contract="RoutingGateway.IRoutingService" behaviorConfiguration="RESTBehaviour" />
  </service>
</services>

<client>
  <endpoint binding="webHttpBinding" bindingConfiguration="secureWebHttpBinding" contract="RoutingGateway.IRoutingService" name="routingService" behaviorConfiguration="RESTBehaviour" />
</client>

<!-- 
    Bindings
-->
<bindings>
  <webHttpBinding>
    <binding name="secureWebHttpBinding" hostNameComparisonMode="StrongWildcard" maxReceivedMessageSize="2147483647" transferMode="Streamed">
      <security mode="Transport">
        <transport clientCredentialType="None" />
      </security>
    </binding>
  </webHttpBinding>
</bindings>

<!-- 
    Behaviors
-->
<behaviors>
  <endpointBehaviors>
    <behavior name="RESTBehaviour">
      <dispatcherSynchronization asynchronousSendEnabled="true" />
      <webHttp helpEnabled="true" />
    </behavior>
  </endpointBehaviors>

  <serviceBehaviors>
    <behavior>
      <!-- To avoid disclosing metadata information, set the value below to false before deployment -->
      <serviceMetadata httpsGetEnabled="false" />
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="false" />
      <!-- Enable Throttling -->
      <serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" maxConcurrentSessions="100" />
    </behavior>
  </serviceBehaviors>
</behaviors>

<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

IRoutingService.cs:

[ServiceContract(Namespace = "https://test/api/routing")]
public interface IRoutingService
{
    [OperationContract(Action = "*", ReplyAction = "*")]
    [WebInvoke(UriTemplate = "*", Method = "*")]
    Message ProcessRequest(Message requestMessage);
}

RoutingService.cs:

public Message ProcessRequest(Message requestMessage)
{
    ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;

    Uri originalRequestUri = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri;

    // Gets the URI depending on the query parameters
    Uri uri = GetUriForRequest(requestMessage);

    // Select rest client endpoint
    string endpoint = "routingService";
    // Create channel factory
    var factory = new ChannelFactory<IRoutingService>(endpoint);

    Uri requestUri = new Uri(uri, originalRequestUri.PathAndQuery);
    factory.Endpoint.Address = new EndpointAddress(requestUri);
    requestMessage.Headers.To = requestUri;

    // Create client channel
    _client = factory.CreateChannel();

    // Begin request
    Message result = _client.ProcessRequest(requestMessage);
    return result;
}

1 个答案:

答案 0 :(得分:1)

我最终捕获了所有的CommunicationExceptions,然后使用适当的消息和状态代码重新抛出WebFaultExceptions。

以下是代码:

Message result = null;
try
{
    result = _client.ProcessRequest(requestMessage);
}
catch (CommunicationException ex)
{
    if (ex.InnerException == null ||
        !(ex.InnerException is WebException))
    {
        throw new WebFaultException<string>("An unknown internal Server Error occurred.",
            HttpStatusCode.InternalServerError);
    }
    else
    {
        var webException = ex.InnerException as WebException;
        var webResponse = webException.Response as HttpWebResponse;

        if (webResponse == null)
        {
            throw new WebFaultException<string>(webException.Message, HttpStatusCode.InternalServerError);
        }
        else
        {
            var responseStream = webResponse.GetResponseStream();
            string message = string.Empty;
            if (responseStream != null)
            {
                using (StreamReader sr = new StreamReader(responseStream))
                {
                    message = sr.ReadToEnd();
                }
                throw new WebFaultException<string>(message, webResponse.StatusCode);
            }
            else
            {
                throw new WebFaultException<string>(webException.Message, webResponse.StatusCode);                            
            }
        }
    }
}