WCF REST service url routing based on query parameters

时光怂恿深爱的人放手 提交于 2020-01-04 14:14:15

问题


Since WCF routing doesn't support routing for REST services, I created a REST service that has one enpoint which accepts all incoming requests and than redirects those requests based on the query parameters.
I did this by following this article http://blog.tonysneed.com/2012/04/24/roll-your-own-rest-ful-wcf-router/.

This approach works for passing through requests and returning the results. The problem is whenever I get an error, like a 404, from the actual service the message that is returned to the client is a 400 (Bad Request).
What I would like to have is a routing proxy that actually just redirects the calls to the real service based on the query and returns all the errors to the client as they come from the real service.

Is this even the right approach to what I'm trying to accomplish, or are there easier or better solutions?

Any help is appreciated!

In the following I added what my code looks like.
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:


I ended up catching all CommunicationExceptions and then rethrowing WebFaultExceptions with the appropriate messages and status codes.

Here is the code:

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


来源:https://stackoverflow.com/questions/30572640/wcf-rest-service-url-routing-based-on-query-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!