Search code examples
wcfuritemplatewebinvoke

Is it possible to change the UriTemplate at runtime


I have the following WebInvoke Attribute:

        [OperationContract]
        [WebInvoke(
        Method         = "POST",
        UriTemplate    = "",
        BodyStyle      = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Json,
        RequestFormat  = WebMessageFormat.Json)]

I would like the UriTemplate value to be set based on a runtime value. Is there any way to set the UriTemplate in the service implementation at runtime?


Solution

  • Yes, you can do that, if you use an endpoint behavior which is added before the WebHttpBehavior. This behavior can change the properties of the WebGetAttribute/WebInvokeAttribute. The code below shows an example of a behavior which changes the UriTemplate property of a [WebGet], but it would work just as well for [WebInvoke].

    public class StackOverflow_7590279
    {
        [ServiceContract]
        public class Service
        {
            [WebGet(UriTemplate = "/Add?x={x}&y={y}", ResponseFormat = WebMessageFormat.Json)]
            public int Add(int x, int y)
            {
                return x + y;
            }
        }
        public class MyBehavior : IEndpointBehavior
        {
            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
            {
            }
    
            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
            }
    
            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
                foreach (OperationDescription od in endpoint.Contract.Operations)
                {
                    if (od.Name == "Add")
                    {
                        WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
                        if (wga != null)
                        {
                            wga.UriTemplate = "/Add?first={x}&second={y}";
                        }
                    }
                }
            }
    
            public void Validate(ServiceEndpoint endpoint)
            {
            }
        }
        public static void Test()
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            var endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
    
            // This has to go BEFORE WebHttpBehavior
            endpoint.Behaviors.Add(new MyBehavior());
    
            endpoint.Behaviors.Add(new WebHttpBehavior());
    
            host.Open();
            Console.WriteLine("Host opened");
    
            WebClient c = new WebClient();
            Console.WriteLine("Using the original template (values won't be received)");
            Console.WriteLine(c.DownloadString(baseAddress + "/Add?x=45&y=67"));
    
            c = new WebClient();
            Console.WriteLine("Using the modified template (will work out fine)");
            Console.WriteLine(c.DownloadString(baseAddress + "/Add?first=45&second=67"));
    
            Console.Write("Press ENTER to close the host");
            Console.ReadLine();
            host.Close();
        }
    }