Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ServiceStack deployment in IIS (404 exception)

I have looked a lot into ServiceStack question on Stackoverflow and really running out of options. Spent a lot of time and tried a lot of options but not being able to run my ServiceStack services in IIS.

I have a virtual directory under default website named api and the physical location pointing that to is bin directory of ServiceStack assemblies.

Just for testing I have put an index.htm in the bin folder. When I navigate to localhost/api, I get the contents of index.htm from bin folder.

However as you see in below code, my client invocation of ServiceStack service via JSONServiceClient results in 404 exception. I am not sure what am I missing.

Thanks much in advance.

  • Service Stack version: 3.9.69.0
  • IIS version 8.0

using System.Configuration;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.SqlServer;

//  logging
using ServiceStack.Logging;

//  Service Interface project
public class xxxService   : Service
{
    public List<xxxResponse> Get(xxxQuery xxxQuery) 
}

[Route("/xxxFeature/{xxxSerialNo}/{xxxVersion}")]
public class xxxQuery : IReturn<List<xxxResponse>>
{
    public string xxxSerialNo { get; set; }
    public string xxxVersion { get; set; }
    public string xxxId { get; set; }
    public string xxxName { get; set; }
}

public class xxxResponse
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Version { get; set; }
    public string Size { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}

Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
  </configSections>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <location path="api"> 
    <system.web>
      <httpHandlers>
        <add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
      </httpHandlers>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    <!-- Required for IIS7 -->
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true" />
      <validation validateIntegratedModeConfiguration="false" />
      <handlers>
        <add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
      </handlers>
    </system.webServer>
  </location>
  <system.webServer>
    <directoryBrowse enabled="false" />
  </system.webServer>
</configuration>

Global.asax.cs

public class Global : System.Web.HttpApplication
{
    public class xxxServiceAppHost : AppHostBase
    {
        public xxxServiceAppHost() : base("xxx Services", typeof(xxxService).Assembly)
        {
            ServiceStack.Logging.LogManager.LogFactory = new Log4NetFactory(true);
            Log4NetUtils.ConfigureLog4Net(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ServerDB"]].ConnectionString);
        }

        public override void Configure(Funq.Container container)
        {
            container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ServerDB"]].ConnectionString, SqlServerDialect.Provider));
            SetConfig(new EndpointHostConfig { ServiceStackHandlerFactoryPath = "api" });
        }
    }

Have also tried with routes.ignore commented To avoid conflicts with ASP.NET MVC add ignore rule in Global.asax. RegisterRoutes method e.g: routes.IgnoreRoute ("api/{*pathInfo}");

    public void RegisterRoutes(RouteCollection routes)
    {
        routes.Ignore("api/{*pathInfo}");
    }

    protected void Application_Start(object sender, EventArgs e)
    {
        new xxxServiceAppHost().Init();
    }
}

Client invocation. I have also tried with ..../api/api because my vdir on IIS is api.

try
{
    xxxServiceClient = new JsonServiceClient("http://111.16.11.111/api");
    List<xxxResponse> xxxResponses = xxxServiceClient.Get(new xxxQuery { xxxSerialNo = "22222", xxxVersion = "0.0" });
}
catch (WebServiceException excp)
{
    throw excp;
}
like image 205
user179400 Avatar asked Jan 10 '14 22:01

user179400


1 Answers

It looks to me like there are a few things you can try with the web.config. You shoudln't need to have a virtual directory on the server. Depending on the version of IIS you are using you might still need both the httpHandlers and handlers config sections. I see your nesting the config settings for ServiceStack in the location path="api". That might make sense for your desired security requirements and why it is that you have an "api" virtual directory. You could try not using that location element.

Try the following: remove the location element and combine settings with your other config sections (system.web...etc), remove the httpHandlers section, keep the handlers section, and change the handlers config to have a path of "api*.

That will map the url to the services so the when you go to localhost:12345/api/metadata you should see your services. If you can't see the metadata page you know something isn't right.

independent of the web.config changes, there are issues with your service code. Your code seems to have a few things out of place. Your request object (xxxQuery) should be a simple POCO with your route attributes. The Get service needs to have that object as its parameter. The response should implement IHasResponseStatus if you are going to return that property.

<handlers>
    <add path="api*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>
</handlers>

//  Service Interface project
public class xxxService   : Service
{
    public xxxResponse Get(xxxQuery xxxQuery)
    { 
        //return object of type xxxResponse after doing some work to get data
        return new xxxResponse();
    } 
}

[Route("/xxxFeature/{xxxSerialNo}/{xxxVersion}")]
public class xxxQuery
{
    public string xxxSerialNo { get; set; }
    public string xxxVersion { get; set; }
    public string xxxId { get; set; }
    public string xxxName { get; set; }
}

public class xxxResponse : IHasResponseStatus
{
    public xxxResponse()
    {
        // new up properties in the constructor to prevent null reference issues in the client
        ResponseStatus  = new ResponseStatus();
    }

    public int ID { get; set; }
    public string Name { get; set; }
    public string Version { get; set; }
    public string Size { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}
like image 180
A Newton Avatar answered Oct 04 '22 00:10

A Newton