Mr_LinDowsMac
Mr_LinDowsMac

Reputation: 2702

Can't properly host a WCF Service in IIS. Error 404

I have requirement that I want a WCF service library that provide a PDF via REST. For example I have an url like this: localhost:8732/service1/reports/ok And I get a PDF as response. It is a fixed file in local filesystem. Here it is my current code:

Service.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfJsonRestService
{

    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
    [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
    public class Service1 : IService1
    {

        public Stream GetReport(string value)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/pdf";
            FileStream f = new FileStream("C:\\invoice.pdf", FileMode.Open);
            int length = (int)f.Length;
            WebOperationContext.Current.OutgoingResponse.ContentLength = length;
            byte[] buffer = new byte[length];
            int sum = 0;
            int count;
            while ((count = f.Read(buffer, sum, length - sum)) > 0)
            {
                sum += count;
            }
            f.Close();
            return new MemoryStream(buffer); 
        }

    }
}

IService.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfJsonRestService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IService1
    {
        // TODO: Add your service operations here

        [OperationContract(Action = "*")]
        [WebInvoke(Method = "GET", //Este metodo si esta en POST, te dice que metodo no permitido
            UriTemplate = "reports/{value}")]
        Stream GetReport(string value);
    }

    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    // You can add XSD files into the project. After building the project, you can directly use the data types defined there, with the namespace "WcfJsonRestService.ContractType".
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
  <system.serviceModel>
    <services>
      <service name="WcfJsonRestService.Service1">
        <endpoint address="http://localhost:8732/service1"
              binding="webHttpBinding"
              contract="WcfJsonRestService.IService1"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior>
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.1" sku=".NETFramework,Version=v4.1"/>
  </startup>
</configuration>

Please, don't pay attention to that misleading name "WcfJsonRestService" that name will be changed later to a more properly one...

Everything is fine when I run this in Visual Studio 2013 (except a warning from Microsoft WCF Service Host that doesn't find any service metadata). When I visit http://localhost:8732/service1/somerandomstring the pdf is opened by the browser. (please note it is a fixed directory on my filesystem for the moment...)

The problem is when I try publish or host . I followed several tutorials about hosting in IIS with no success. How I should do to make this working?

OS: Windows 8.1 .NET Framework 4

Upvotes: 2

Views: 6050

Answers (3)

Darkseal
Darkseal

Reputation: 9564

I stumbled upon this issue a couple days ago: it was due to the missing handler mapping which is required to hanle this type of call. There are several ways to work around the problem, such as manually execute the ServiceModelReg.exe console command. The resolution method I propose below is more complex, but it has the advantage of fixing that specific issue without changing the default behavior of the web server, thus avoding potential side-effects.

  • Open the Server Manager interface for machine management, usually present in both the Task Bar and the Start menu.
  • Go to the Dashboard and select Add Role or Feature to open the Wizard.
  • Select the Role-based or Feature-based installation type and the server you want to work on, that is, your local / local server.
  • Go to the Features section: Once there, expand the .NET Framework 3.5 Features node and / or the .NET Framework 3.5 Features node, depending on what you have installed: if you have both, you should perform the following step twice (for each one of them).
  • Expand the WCF Services section (if available), then select HTTP Activation (see screenshot below).
  • Continue until you complete the Wizard, then click Install.

enter image description here

Once the installation is complete, you should be able to run your WCF Service without incurring in the 404 error ever again.

For additional info regarding this specific issue and how to fix it, you can also read this post on my blog.

Upvotes: 5

Sandeep Kushwah
Sandeep Kushwah

Reputation: 592

I have tried to populate the problem on my machine and I got it. I found the solution as well. After hosting in IIS. The url you visit to hit the service will be http://localhost/<name of the site while hosting to iis>/<namespaceofyourservice>.<servicename>/<method name>. So for my case it became http://localhost/WcfJSONPDF/WcfJsonRestService.Service1.svc/reports/ok. Here "ok" is the string passed to the web method. I know its strange that we have to pass namespace as well in the url but you have to accept it for now. I will look for some workaround. Here is the Image of url definition : url definition .
Here is steps to publish your Wcf Service Library Project to IIS7. Please see below Image : Image
Click on Build-->Publish Webservice-->Name the url(website name)-->Click on publish button-->Click publish on Local IIS.
Thats all. I hope you will get the desired output.
If you still have some issues then update App.config with the below one:

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="WcfJsonRestService.Service1" behaviorConfiguration="Metadata">
        <endpoint address=""
              binding="webHttpBinding"
              contract="WcfJsonRestService.IService1" behaviorConfiguration="Restbeh"/>
        <endpoint name="mex"
               address="mex"
               binding="mexHttpBinding"
               contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:80/service1" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="Restbeh">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="Metadata">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.1" sku=".NETFramework,Version=v4.1"/>
  </startup>
</configuration>

Upvotes: 2

Matt
Matt

Reputation: 13349

Could be a permission issue, when hosting in IIS you need to give read permission to the identity that your site is running under to that folder and its contents. Which identity you're running under will depend on which version of IIS you're using and how you've configured your app pool. You can check which identity it is by looking at the advanced settings of your app pool and scrolling down to identity. Then check the security settings on your pdf folder for this user.

Upvotes: 0

Related Questions