Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7554931
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 30, 20262026-05-30T11:28:01+00:00 2026-05-30T11:28:01+00:00

Consider the following two WCF 4.0 REST services: [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode =

  • 0

Consider the following two WCF 4.0 REST services:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class WorkspaceService
{
    [WebInvoke(UriTemplate = "{id}/documents/{name}", Method = "POST")]
    public Document CreateWorkspaceDocument(Stream stream, string id, string name) 
    {
        /* CreateDocument is omitted as it isn't relevant to the question */
        Document response = CreateDocument(id, name, stream);

        /* set the location header */
        SetLocationHeader(response.Id);
    }

    private void SetLocationHeader(string id)
    {   
        Uri uri = new Uri("https://example.com/documents/" + id);
        WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(uri);
    }

    /* methods to delete, update etc */
}

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class DocumentService
{

    [WebGet(UriTemplate = "{id}")]
    public Document GetDocument(string id)
    {
    }

    /* methods to delete, update etc */
}

In essence, when someone creates a document in a workspace, the Location header is set to the location of the document, which is essentially is the same as invoking the DocumentService.GetDocument operation.

My global.asax looks as follows:

public class Global : HttpApplication
{
    private void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes();
    }

    private void RegisterRoutes()
    {
        var webServiceHostFactory = new WebServiceHostFactory();
        RouteTable.Routes.Add(new ServiceRoute("workspaces", webServiceHostFactory, typeof (WorkspaceService)));
        RouteTable.Routes.Add(new ServiceRoute("documents", webServiceHostFactory, typeof (DocumentService)));
        /* other services */
    }
}

The implementation of WorkspaceService.SetLocationHeader as it makes some assumptions about how routing was setup. If I was to change the route of DocumentService then the resulting Uri will be incorrect. If I changed the UriTemplate of DocumentService.GetDocument, then the resulting Uri will be incorrect too.

If WorkspaceService and DocumentService was merged into one service, I could have written SetLocationHeader as follows:

var itemTemplate = WebOperationContext.Current.GetUriTemplate("GetDocument");
var uri = itemTemplate.BindByPosition(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri, id);
WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(uri);

How would one write WorkspaceService.SetLocationHeader such that it will use the routing table defined in Global.asax and UriTemplates to return the Uri for the GetDocument operation of the DocumentService?

I’m using plain old WCF 4.0 (not the WCF Web API).

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-30T11:28:02+00:00Added an answer on May 30, 2026 at 11:28 am

    By accident, I found the an article written by José F. Romaniello which shows how to do it for the WCF Web API and adapted it. The source code is at the end of the answer.

    Assuming I have four services, the routing registration changes to use a subclass of ServiceRoute which we later use to “evaluate” when scanning the routing table.

    using System;
    using System.Web;
    using System.Web.Routing;
    
    public class Global : HttpApplication
    {
        private void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }
    
        private void RegisterRoutes()
        {
            RouteTable.Routes.Add(new ServiceRoute<Service1>("s1"));
            RouteTable.Routes.Add(new ServiceRoute<Service2>("s2"));
            RouteTable.Routes.Add(new ServiceRoute<Service3>("s3"));
            RouteTable.Routes.Add(new ServiceRoute<Service4>("s4"));
        }
    }
    

    The WorkspaceService.SetLocationHeader now looks as follows:

    private void SetLocationHeader(string id)
    {   
        ResourceLinker resourceLinker = new ResourceLinker();
    
        Uri uri = resourceLinker.GetUri<WorkspaceService>(s => s.Get(id));
        WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(uri);
    }
    

    The same code snippet can be used to set the uri of a workspace from other services, such as DocumentService.Get

    [WebGet("{id}")]
    public Document Get(string id)
    {
        // can be static
        ResourceLinker resourceLinker = new ResourceLinker();
    
        DocumentEntity entity = _repository.FindById(id);
        Document document = new Document();
        document.Name = entity.Name; 
        // map other properties
        document.Workspace.Name = entity.Workspace.Name;
        document.Workspace.Uri = resourceLinker.GetUri<WorkspaceService>(s => s.Get("0"));
        // map other properties
        return document;
    }
    

    With this approach there are no magic strings and its unlikely that a change to a method name, service name, routing table prefix will break the system.

    Here is the implementation adapted from the article :

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Web;
    using System.Web.Routing;
    
    public interface IServiceRoute
    {
        Type ServiceType
        {
            get;
        }
    
        string RoutePrefix
        {
            get;
            set;
        }
    }
    
    public class ServiceRoute<T> : ServiceRoute, IServiceRoute
    {
        public ServiceRoute(string routePrefix) : this(routePrefix, new WebServiceHostFactory())
        {
        }
    
        public ServiceRoute(string routePrefix, ServiceHostFactoryBase serviceHostFactory)
            : base(routePrefix, serviceHostFactory, typeof (T))
        {
            RoutePrefix = routePrefix;
            ServiceType = typeof (T);
        }
    
        #region IServiceRoute Members
    
        public string RoutePrefix
        {
            get;
            set;
        }
    
        public Type ServiceType
        {
            get;
            private set;
        }
    
        #endregion
    }
    
    public static class RouteTableExtensions
    {
        public static void AddService<T>(this RouteCollection routeCollection, string routePrefix)
        {
            routeCollection.Add(new ServiceRoute<T>(routePrefix));
        }
    
        public static string GetRoutePrefixForType<T>(this RouteCollection routeCollection)
        {
            var routeServiceType = routeCollection
                .OfType<IServiceRoute>()
                .FirstOrDefault(r => r.ServiceType == typeof (T));
            if (routeServiceType != null)
            {
                return routeServiceType.RoutePrefix;
            }
            return null;
        }
    }
    
    public interface IResourceLinker
    {
        Uri GetUri<T>(Expression<Action<T>> restMethod);
    }
    
    public class ResourceLinker : IResourceLinker
    {
        private readonly Uri _baseUri;
    
        public ResourceLinker()
            : this("http://localhost:53865")
        {
        }
    
        public ResourceLinker(string baseUri)
        {
            _baseUri = new Uri(baseUri, UriKind.Absolute);
        }
    
        #region IResourceLinker Members
    
        public Uri GetUri<T>(Expression<Action<T>> restMethod)
        {
            var methodCallExpression = (MethodCallExpression) restMethod.Body;
            var uriTemplateForMethod = GetUriTemplateForMethod(methodCallExpression.Method);
    
            var args = methodCallExpression.Method
                .GetParameters()
                .Where(p => uriTemplateForMethod.Contains("{" + p.Name + "}"))
                .ToDictionary(p => p.Name, p => ValuateExpression(methodCallExpression, p));
    
            var prefix = RouteTable.Routes.GetRoutePrefixForType<T>();
            var newBaseUri = new Uri(_baseUri, prefix);
            var uriMethod = new UriTemplate(uriTemplateForMethod, true);
            return uriMethod.BindByName(newBaseUri, args);
        }
    
        #endregion
    
        private static string ValuateExpression(MethodCallExpression methodCallExpression, ParameterInfo p)
        {
            var argument = methodCallExpression.Arguments[p.Position];
            var constantExpression = argument as ConstantExpression;
            if (constantExpression != null)
            {
                return constantExpression.Value.ToString();
            }
    
            //var memberExpression = (argument as MemberExpression);
            var lambdaExpression = Expression.Lambda(argument, Enumerable.Empty<ParameterExpression>());
            var result = lambdaExpression.Compile().DynamicInvoke().ToString();
            return result;
        }
    
        private static string GetUriTemplateForMethod(MethodInfo method)
        {
            var webGet = method.GetCustomAttributes(true).OfType<WebGetAttribute>().FirstOrDefault();
            if (webGet != null)
            {
                return webGet.UriTemplate ?? method.Name;
            }
    
            var webInvoke = method.GetCustomAttributes(true).OfType<WebInvokeAttribute>().FirstOrDefault();
            if (webInvoke != null)
            {
                return webInvoke.UriTemplate ?? method.Name;
            }
    
            throw new InvalidOperationException(string.Format("The method {0} is not a web method.", method.Name));
        }
    }
    

    The default constructor of ResourceLinker requires some changes to pick up the base uri of the web application, taking into account that HTTPS may be terminated at the load balancer. That falls outside of this answer.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Consider the following two scenarios: //Data Contract public class MyValue { } Scenario 1:
consider the following two pieces of code: public static Time Parse(string value) { string
Consider the following two classes public class ServerDAOHb implements Serializable { .... @OneToMany(cascade =
Consider the following two ways of writing a loop in Java to see if
Consider the following two alternatives: console.log("double"); console.log('single'); The former uses double quotes around the
Consider the following two Java files that contain a simplified version of my issue
Do splitting fields into multiple tables ever yield faster queries? Consider the following two
I'm a bit puzzled about the conditional operator. Consider the following two lines: Float
Let's consider the two following lines in C# (using framework .NET 3.5) Regex regex
Consider the following situation: We have two Localizable.string files, one in en.lproj and one

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.