c# - 基于查询参数的 WCF REST 服务 url 路由

标签 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(错误请求)。
我想要的是一个路由代理,它实际上只是根据查询将调用重定向到真实服务,并将所有错误返回给客户端,因为它们来自真实服务。

这是否是我想要完成的目标的正确方法,或者是否有更简单或更好的解决方案?

感谢任何帮助!

在下面我添加了我的代码。
应用程序配置:

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

路由服务.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;
}

最佳答案

我最终捕获了所有 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);                            
            }
        }
    }
}

关于c# - 基于查询参数的 WCF REST 服务 url 路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30572640/

相关文章:

c# - 如何在Sand CaSTLe/MAML的代码示例中为类名称着色

c# - 为什么这些任务顺序执行?

c# - Selenium Chrome 驱动程序(75 及以上)使用 GetLog() 方法访问日志时出现问题

asp.net - 没有端点监听并且错误 404

通过 wsimport 可执行 Web 服务客户端时出现 java 异常

java - C# WCF 客户端绑定(bind) 互操作 Blackboard Java WS-Security over HTTPS 传输

c# - 将 ASMX 转换为 WCF Web 服务需要付出多少努力?

c# - 如何在 Quartz.net 的 Interrupt 方法中访问 IJobexecutionContext?

c# - 通过 Web 服务自动公开数据库表

web-services - Mechanical Turk 文件上传