locked
Rewriting request URL (Best practice) RRS feed

  • Question

  • Hello,

    I have created a data service that uses an EF provider and have a unique requirement that is necessitated by the multi-tenancy nature of my database. (You can see my requirement outlined here)

    The resolution I have come-up with feels a bit clunky but appears to work. Essentially, I am intercepting the incoming request in the IDispatchMessageInspector implementation, removing the clientid and rewriting the request in the OperationContext.

    Code:

    public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
            {
                HttpRequestMessageProperty httpmsg = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
               // ...Additional logic for handling Query formats in OData
    			
    			
                UriTemplate template = new UriTemplate("mysamplesvc/{ClientId}", true);
    
                Uri prefix = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority));
                Uri uri = new Uri(HttpContext.Current.Request.Url.AbsoluteUri);
                UriTemplateMatch results = template.Match(prefix, uri);
                
                if (results != null && !string.IsNullOrEmpty(results.BoundVariables["ClientId"]))
                {
                    _clientId = results.BoundVariables["ClientId"].ToString();
                }
    
                if (!string.IsNullOrEmpty(_clientId))
                {
                    httpmsg.Headers.Add("ClientId", _clientId);
                    rewriteRequest();
                }
                return null;
            }
    
            private void rewriteRequest()
            {
                if (HttpContext.Current != null && HttpContext.Current.Session != null)
                {
                    if (WebOperationContext.Current.IncomingRequest.UriTemplateMatch != null)
                    {
                        Uri serviceUri = HttpContext.Current.Session["ServiceUri"] as Uri;
                        Uri requestUri = null;
    
                        UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
    
                        if (serviceUri == null)
                        {
                            UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri);
    
                            serviceUri = serviceUriBuilder.Uri;
                            HttpContext.Current.Session["ServiceUri"] = serviceUri;
                        }
    
                        if (serviceUri != null)
                        {
                            OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = serviceUri;
    
                            UriBuilder requestUriBuilder = new UriBuilder(match.RequestUri);
                            string path = string.Empty;
                            if (match.RelativePathSegments[0] == _clientId)
                            {
                                foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
                                {
                                    if (seg.Index != 0)
                                    {
                                        path += "/";
                                        path += seg.Value;
                                    }
                                }
                            }
                            else
                            {
                                foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
                                {
                                    path += "/";
                                    path += seg.Value;
                                }
                            }
    
                            UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri + path);
    						
                            // because we have overwritten the Root URI, we need to make sure the request URI shares the same host
                            // (sometimes we have request URI resolving to a different host, if there are firewall re-directs
                            serviceUriBuilder.Host = serviceUri.Host;
    
                            requestUri = serviceUriBuilder.Uri;
                            OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = requestUri;
                            OperationContext.Current.IncomingMessageProperties["Via"] = requestUri;
                        }
                    }
    
                }
            }



    However, I am looking for guidance as to how best to acheive this result in a more elegant manner. And, ultimately, I would like to redirect the requests in the appropriate manner while leaving the browser url and links for navigation properties in place if possible. I'm sure I have hacked this and may have missed some big gotchas so I am hoping someone could point these errors out or possibly point me to an example of a better way to do this.

    Best regards,

    Ryan


    • Edited by rkbrown Tuesday, December 13, 2011 5:17 PM Formatting change
    Tuesday, December 13, 2011 5:03 PM

All replies