none
Cannot pass a filename as a URI template parameter

    Question

  • I am developing a WCF service application.

    1) I have a simple Operation contract:

    [OperationContract]
    [WebGet(ResponseFormat=WebMessageFormat.Xml,
                  UriTemplate = "resource/{resourceName}")]
    System.IO.Stream resource(string resourceName);
    2) I have configured the web.config file for webHttpBinding with the appropriate endpoint and endpoint behavior for webHttpBinding.

    When I host the local service locally, I get a resource cannot be found if I pass in a filename with an extension on the uri.

    Example:  http://localhost:2250/service.svc/web/aaa.txt      The browser returns "The resource cannot be found"
                    http://localhost:2250/service.svc/web/aaa          The resource is found and my contract implementation code is entered.

    What am I missing?

    Friday, May 8, 2009 6:31 PM

Answers

  • how about if you change the OC to be

    WebGet(ResponseFormat=WebMessageFormat.Xml,              UriTemplate = "resource/{resourceName}.{ext}")]
    System.IO.Stream resource(string resourceName, string ext);

    Amit
    Friday, May 8, 2009 7:49 PM
    Moderator
  • Ok, here you go, the complete code listing.

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.IO;
    
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "resource/{resourceName}")]
        Stream GetData(string resourceName);
    }
    
    public class MyService : IMyService
    {
        public Stream GetData(string resourceName)
        {
            if (resourceName.Substring(resourceName.LastIndexOf('.') + 1) == "txt")
                WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
    
            byte[] file = File.ReadAllBytes(resourceName);
    
            return new MemoryStream(file);
        }
    }
    
    public class Program
    {
        public static void Main()
        {
            Uri baseAddress = new Uri("http://localhost:50000");
    
            WebServiceHost svcHost = new WebServiceHost(typeof(MyService), baseAddress);
    
            svcHost.Open();
            Console.WriteLine("Service is running");
    
            Console.ReadLine();
            svcHost.Close();
        }
    }



    Fire this up from a console project and navigate your browser to:
    - http://localhost:50000/resource/test.txt -> you'll get the content of the file (text)
    - http://localhost:50000/resource/test      -> you'll get the content as a file (binary)

    Put the 'test.txt' and 'test' files inside of bin/Debug directory of your VS project before testing the service and populate it with custom text.

    Did this help?

    Regards,
    John
    Friday, May 8, 2009 7:53 PM
  • No it should work with period also.  

    [ServiceContract]
            public interface IClientTest
            {
                [OperationContract, WebGet(UriTemplate = "resource/{resourceName}.{ext}", ResponseFormat = WebMessageFormat.Xml)]
                string SimpleGet(string resourceName, string ext);
            }
    
            public class ClientTest : IClientTest
            {
                public string SimpleGet(string resourceName, string ext)
                {
                    return string.Format("You want file {0}.{1}", resourceName, ext);
                }
            }

     public static void Main()
            {
                string baseAddress = @"http://localhost:6001/Service";
                WebServiceHost host = new WebServiceHost(typeof(ClientTest), new Uri(baseAddress));
    
                host.AddServiceEndpoint(typeof(IClientTest), new WebHttpBinding(), baseAddress);
                host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Xml });
    
                host.Open();
                Console.WriteLine("open");
                Console.Read();
                host.Close();
    }

    GET /Service/resource/ff.txt HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:6001

    Response =

    <?xml version="1.0" encoding="utf-8"?><string>You want file ff.txt</string>


    Amit Sharma
    Friday, May 8, 2009 8:09 PM
    Moderator

All replies

  • Hi,

    try adding this to you method implementation:

    WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";


    Did it do the trick?

    Regards,
    John
    Friday, May 8, 2009 7:06 PM
  • skatkovi,

    Did not work. 

    For some reason my service is rejecting the request when it see the "." in the file name.  I have to believe this is some type of configuration issue.  This same contract has worked when it was implemented in a wcf service library.
    Friday, May 8, 2009 7:17 PM
  • how about if you change the OC to be

    WebGet(ResponseFormat=WebMessageFormat.Xml,              UriTemplate = "resource/{resourceName}.{ext}")]
    System.IO.Stream resource(string resourceName, string ext);

    Amit
    Friday, May 8, 2009 7:49 PM
    Moderator
  • Ok, here you go, the complete code listing.

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.IO;
    
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "resource/{resourceName}")]
        Stream GetData(string resourceName);
    }
    
    public class MyService : IMyService
    {
        public Stream GetData(string resourceName)
        {
            if (resourceName.Substring(resourceName.LastIndexOf('.') + 1) == "txt")
                WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
    
            byte[] file = File.ReadAllBytes(resourceName);
    
            return new MemoryStream(file);
        }
    }
    
    public class Program
    {
        public static void Main()
        {
            Uri baseAddress = new Uri("http://localhost:50000");
    
            WebServiceHost svcHost = new WebServiceHost(typeof(MyService), baseAddress);
    
            svcHost.Open();
            Console.WriteLine("Service is running");
    
            Console.ReadLine();
            svcHost.Close();
        }
    }



    Fire this up from a console project and navigate your browser to:
    - http://localhost:50000/resource/test.txt -> you'll get the content of the file (text)
    - http://localhost:50000/resource/test      -> you'll get the content as a file (binary)

    Put the 'test.txt' and 'test' files inside of bin/Debug directory of your VS project before testing the service and populate it with custom text.

    Did this help?

    Regards,
    John
    Friday, May 8, 2009 7:53 PM
  • Amit,

    I have tried that (compound path segments)  as well..Still a no-go.   I saw that "trick" on MSDN at "UriTemplate and UriTemplateTable" http://msdn.microsoft.com/en-us/library/bb675245.aspx.

    If I replace the period with a semicolon, it will work.  e.g. {resourceName};{ext}")]

    This is what is so frustrating.  It should work.
    Friday, May 8, 2009 7:58 PM
  • No it should work with period also.  

    [ServiceContract]
            public interface IClientTest
            {
                [OperationContract, WebGet(UriTemplate = "resource/{resourceName}.{ext}", ResponseFormat = WebMessageFormat.Xml)]
                string SimpleGet(string resourceName, string ext);
            }
    
            public class ClientTest : IClientTest
            {
                public string SimpleGet(string resourceName, string ext)
                {
                    return string.Format("You want file {0}.{1}", resourceName, ext);
                }
            }

     public static void Main()
            {
                string baseAddress = @"http://localhost:6001/Service";
                WebServiceHost host = new WebServiceHost(typeof(ClientTest), new Uri(baseAddress));
    
                host.AddServiceEndpoint(typeof(IClientTest), new WebHttpBinding(), baseAddress);
                host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Xml });
    
                host.Open();
                Console.WriteLine("open");
                Console.Read();
                host.Close();
    }

    GET /Service/resource/ff.txt HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:6001

    Response =

    <?xml version="1.0" encoding="utf-8"?><string>You want file ff.txt</string>


    Amit Sharma
    Friday, May 8, 2009 8:09 PM
    Moderator
  • Slatkovi,

    Your suggestion did in fact work.  I figured that it would.  My service implementation is as basic your's was.   However, I am not creating the service in code the way you did.  I created a WCF Web service application that will be deployed on IIS.  I have the web.config file to deal with and my suspicion is that I have some attribute missing or set wrong that is causing my problem.
    Friday, May 8, 2009 8:36 PM
  • pelase post the ServiceModel section of your config file


    Amit Sharma
    Friday, May 8, 2009 8:42 PM
    Moderator
  • Amit,

    I agree wholeheartedly.  But it did not work for me.  I have the exact OperationContract and implementation as you (except I return a stream) and when the UriTemplate was {resourceName}.{ext}  is does not work.  If I change the UriTemplate to use a ";" it will work.
    Friday, May 8, 2009 8:44 PM
  • <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

    <bindings>
       <webHttpBinding>
          <binding name="WebHttpBinding_IService" sendTimeOut="00:10:00"
               hostNameComparisonMode="StrongWildCard" maxBufferSize="2147483647"
               maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" />
          </binding>
        </webHttpBinding>
     </bindings>

     <services>
        <service behaviorConfiguration="SourceService.SerivceBehavior" name="SourceService.Service">
             <endpoint address="" behaviorConfiguration="WebEndPointBehavior"
                    binding="webHttpBinding"  bindingConfiguration="WebHttpBinding_IService"
                    name="RestEndPoint" bindingName="REST_Binding" contract="SourceService.IService" />
         </service>
    </services>

    <behaviors>
         <endpointBehaviors>
            <behavior name="WebEndPointBehavior">
                 <webHttp/>
             </behavior>
         </endpointBehaviors>
          <serviceBehaviors>
            <behavior name="SourceService.ServiceBehavior">
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
          </serviceBehaviors>
    </behaviors>
    </system.serviceModel>
    Friday, May 8, 2009 9:09 PM
  • I am not very familiar with the webHttpBinding configuration, but a simple config like the one below should be enough for a REST service.
    You can start with this config below and then add the binding configuration later on, if your design wants such a service configuration.

    <configuration>
        <system.serviceModel>
            <behaviors>
                <endpointBehaviors>
                    <behavior name="Test_Behavior">
                        <webHttp />
                    </behavior>
                </endpointBehaviors>
            </behaviors>
            <services>
                <service name="SourceService.Service">
                    <endpoint behaviorConfiguration="Test_Behavior" binding="webHttpBinding"
                        contract="SourceService.IService" />
                </service>
            </services>
        </system.serviceModel>
        <system.web>
         
        </system.web>
    </configuration>

    also, can you please confirm that your .svc file has the factory attribute set to : Factory="System.ServiceModel.Activation.WebServiceHostFactory"
    eg:
    <%@ServiceHost language=c# Service="SourceService.Service" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
    Amit Sharma
    Friday, May 8, 2009 9:45 PM
    Moderator
  • I've managed to reproduce the behavior indicated in the original post. Strange thing is that it only occurs when the service is hosted under the ASP.NET Development Server - once I move it to the IIS it works just fine.

    Any thoughts?

    Regards,
    John
    Saturday, May 9, 2009 12:32 AM
  • I will followup with the cassini folks about this.

    Until then I believe that the scenario works in IIS and self hosted, so I am going to assume that these two hosting environments are ok as a work around for the cassini issue. 
    If I hear back form the cassini folks, I will update this post accordingly.
    Amit Sharma
    Monday, May 11, 2009 8:01 PM
    Moderator
  • Amit,

    I hosted my service in IIS and it works!  So maybe cassini will be able to either confirm the problem or provide a solution/work around.

    Thx 
    Tuesday, May 12, 2009 6:07 PM