问题描述
由于 WCF 路由不支持 REST 服务的路由,因此我创建了一个 REST 服务,该服务具有一个端点,该端点接受所有传入请求,然后根据查询参数重定向这些请求.
我按照这篇文章http://blog.tonysneed.com/2012/04/24/roll-your-own-rest-ful-wcf-router/.
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/.
此方法适用于传递请求并返回结果.问题是,每当我从实际服务中收到错误(如 404)时,返回给客户端的消息是 400(错误请求).
我想要的是一个路由代理,它实际上只是根据查询将调用重定向到真实服务,并将所有错误返回给客户端,因为它们来自真实服务.
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?
感谢任何帮助!
在下面我添加了我的代码的样子.
应用程序配置:
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:
IRoutingService.cs:
[ServiceContract(Namespace = "https://test/api/routing")]
public interface IRoutingService
{
[OperationContract(Action = "*", ReplyAction = "*")]
[WebInvoke(UriTemplate = "*", Method = "*")]
Message ProcessRequest(Message requestMessage);
}
RoutingService.cs:
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;
}
推荐答案
我最终捕获了所有 CommunicationExceptions,然后使用适当的消息和状态代码重新抛出 WebFaultExceptions.
I ended up catching all CommunicationExceptions and then rethrowing WebFaultExceptions with the appropriate messages and status codes.
代码如下:
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);
}
}
}
}
这篇关于基于查询参数的WCF REST服务url路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!