madhouse
madhouse

Reputation: 183

Owin Hosted NancyFX app returns Could not load type Nancy.Hosting.Aspnet.NancyHttpRequestHandler once published to IIS

While it works perfectly when run locally through VS Studio's included IIS Express, my application chokes once deployed to IIS 8:

System.Web.HttpException: Could not load type 'Nancy.Hosting.Aspnet.NancyHttpRequestHandler'.

Back-end is MS Owin, written in VB (.NET 4.5), which registers 3 middlewares: OAuth server, JWT bearer Authentication, and Nancy. Front end is AngularJS. The proper DLLs are included in the published directory.

IIS 8 has .NET 4.5 installed and enabled. It is running in integrated mode.

I am not sure if this is related to the configuration of Nancy within web.config or the configuration of IIS. Relevant source follows:

Startup.vb

Public Sub Configuration(app As IAppBuilder)

        Dim issuer As String = "http://obscured-domain"
        Dim audience As String = "obscured-audience-key"
        Dim secret As Byte() = Microsoft.Owin.Security.DataHandler.Encoder.TextEncodings.Base64Url.Decode("obscured-client-secret")

        'CORS Configuration
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll)
        app.UseOAuthAuthorizationServer(New OAuthAuthorizationServerOptions() With { _
                                    .AllowInsecureHttp = True, _
                                    .TokenEndpointPath = New PathString("/authenticate"), _
                                    .AccessTokenExpireTimeSpan = TimeSpan.FromHours(1), _
                                    .AccessTokenFormat = New JwtFormat(issuer, audience), _
                                    .Provider = New OAuthServerProvider()
                                })
        app.UseJwtBearerAuthentication(New JwtBearerAuthenticationOptions() With { _
                                       .AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active, _
                                       .AllowedAudiences = New String() {audience}, _
                                       .IssuerSecurityTokenProviders = New IIssuerSecurityTokenProvider() { _
                                           New SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                                       }
                                   })
        'Content service
        Dim nOpts As New NancyOptions
        nOpts.PassThroughWhenStatusCodesAre(HttpStatusCode.NotFound, HttpStatusCode.InternalServerError)
        app.UseNancy(nOpts)
        'Handle IIS request pipeline staging
        app.UseStageMarker(PipelineStage.MapHandler)
    End Sub

Web.config

    <?xml version="1.0"?>
<configuration>
  <system.web>
    <customErrors mode="Off" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <httpHandlers>
      <add verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
    </httpHandlers>
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <add name="Nancy" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*"/>
    </handlers>
  </system.webServer>
  <connectionStrings>
    <add name="FTConnStr" connectionString="obscured-connection-string" />
  </connectionStrings>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Example Nancy Module

Public Class KnowledgeBaseModule
Inherits NancyModule

    'Get page of article briefs via full-text search
    MyBase.Get("/api/articles/paged/{offset}/{numRows}") = _
    Function(parameters)
            Dim searchFields As FullTextFields = Me.Bind(Of FullTextFields)()
            Try
                Dim results As Dictionary(Of String, List(Of Dictionary(Of String, Object)))
                results = FullTextProvider.pagedSearch(searchFields.fields("SearchString"), CInt(parameters.offset), CInt(parameters.numRows))
                Return Response.AsJson(results)
            Catch ex As Exception
                'temp 500
                Return HttpStatusCode.InternalServerError
            End Try
        End Function

Private Class FullTextFields
    Public Property fields As Dictionary(Of String, String) = New Dictionary(Of String, String) From _
        {
            {"SearchString", String.Empty}
        }
End Class
End Class

Upvotes: 4

Views: 2869

Answers (1)

Brian Surowiec
Brian Surowiec

Reputation: 17281

Since you're using OWIN you need to use the SystemWeb host not Nancy's AspNet host. You also need to remove these two parts from your web.config:

<httpHandlers>
  <add verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
</httpHandlers>

<handlers>
  <add name="Nancy" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*"/>
</handlers>

You probably have a copy of the nancy host in your bin folder which is why it works locally but not when you deploy it.

Upvotes: 4

Related Questions