WCF Data Services Error - 302 Moved on SaveChanges() related to HTTPS + Load Balancer?

 ̄綄美尐妖づ 提交于 2019-12-06 12:49:43
Alex James

The problem here is likely that the self/links edit links are HTTP, not HTTPS, so the client can't use the links to access the data. Per Vitek's scary answer.

The unfortunate thing is the server doesn't know where it is.

I can think of a couple of options (neither of them particularly nice):

  1. Use a custom IDataServiceHost2 that tells Data Services its root is https://... via the AbsoluteServiceUri property. That way Data Services should produce appropriate URLS
  2. Implement a WCF Behavior that strips out http:// urls and replaces them with https://, this would involve a lot of buffering etc. Checkout this JSONP example which modifies responses from the server.

-Alex

Finally solved this nasty issue. There were actually two issues.

Issue #1: WCF Data Service hosted in IIS behind a load balancer with https creates feeds with http URIs rather than https. This is understandable and was my first guess into the issue. Through lots of digging I came across this article which provided a pretty straight forward solution.

In the constructor of my service I hook up to the processing request event

ProcessingPipeline.ProcessingRequest += ProcessingPipeline_ProcessingRequest;

In the event handler, I use the article mentioned and made some tweaks that basically take the host, scheme and port from the clientExpectsUri and applies them to the request Uri. I also just look for a custom header that I called "X-Client-Expects-RootUri" that clients outside the firewall need to send if they want valid feeds.

static void ProcessingPipeline_ProcessingRequest(object sender, DataServiceProcessingPipelineEventArgs e)
{
    if (e.OperationContext.RequestHeaders.AllKeys.Contains(ClientExpectsUriKey))
        ProcessUri(new Uri(e.OperationContext.RequestHeaders[ClientExpectsUriKey]));    
}

private static void ProcessUri(Uri clientExpectsRootUri)
{
    if (clientExpectsRootUri != null)
    {
        var requestUri = OperationContext.Current.IncomingMessageProperties.ContainsKey("MicrosoftDataServicesRequestUri") 
                                ? OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] as Uri : HttpContext.Current.Request.Url;

        var serviceUri = clientExpectsRootUri;

        var serviceUriBuilder = new UriBuilder(serviceUri);

        var requestUriBuilder = new UriBuilder(requestUri)
                                    {
                                        Host = serviceUriBuilder.Host,
                                        Scheme = serviceUriBuilder.Scheme,
                                        Port = serviceUriBuilder.Port
                                    };

        if (!serviceUriBuilder.Path.EndsWith("/")) //the base uri should end with a slash... 
            serviceUriBuilder.Path = serviceUriBuilder.Path += "/";

        OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = serviceUriBuilder.Uri;
        OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = requestUriBuilder.Uri;
    }
}

I would actually like some feedback on this design, as I am basically asking the client to tell me how to return the URI via a custom header. I will be looking into modifying the load balancer in the future to add these headers automatically.

Issue #2: Load balancer was not configured for MERGE and other non-RFC http methods. The solution to this issue was simple, just set usePostTunneling to true on the DataServiceContext. If anyone has the scripts to enable non-RFC http methods for a cisco 11503, I'd love to have them. ;-)

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