5

I am working through Scott Allen's MVC 5 Fundamentals course on Pluralsight

I get an error at "using (WebApp.Start(uri)) " in the code below.

The error is

An unhandled exception of type 'System.ArgumentException' occurred in Microsoft.Owin.dll
  System.ArgumentException was unhandled
  HResult=-2147024809
  Message=No conversion available between ConsoleApplication1.HelloWorldComponent and System.Func`2[System.Collections.Generic.IDictionary`2[System.String,System.Object],System.Threading.Tasks.Task].
Parameter name: signature
  Source=Microsoft.Owin
  ParamName=signature
  StackTrace:
       at Microsoft.Owin.Builder.AppBuilder.Convert(Type signature, Object app)
       at Microsoft.Owin.Builder.AppBuilder.BuildInternal(Type signature)
       at Microsoft.Owin.Builder.AppBuilder.Build(Type returnType)
       at Microsoft.Owin.Hosting.ServerFactory.ServerFactoryAdapter.Create(IAppBuilder builder)
       at Microsoft.Owin.Hosting.Engine.HostingEngine.StartServer(StartContext context)
       at Microsoft.Owin.Hosting.Engine.HostingEngine.Start(StartContext context)
       at Microsoft.Owin.Hosting.Starter.DirectHostingStarter.Start(StartOptions options)
       at Microsoft.Owin.Hosting.Starter.HostingStarter.Start(StartOptions options)
       at Microsoft.Owin.Hosting.WebApp.StartImplementation(IServiceProvider services, StartOptions options)
       at Microsoft.Owin.Hosting.WebApp.Start(StartOptions options)
       at Microsoft.Owin.Hosting.WebApp.Start[TStartup](StartOptions options)
       at Microsoft.Owin.Hosting.WebApp.Start[TStartup](String url)
       at ConsoleApplication1.Program.Main(String[] args) in e:\EShared\Dev2015\WebAppScottAllen\ConsoleApplication1\ConsoleApplication1\Program.cs:line 16
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

The code is

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Owin.Hosting;
using Owin;
namespace ConsoleApplication1
{
    using AppFunc = Func<IDictionary<string, object>, Task>;
    class Program
    {
        static void Main(string[] args)
        {
            string uri = "http://localhost:8080";
            using (WebApp.Start<Startup>(uri))   // Katana Please start, using the configuration from the Startup class and listening on the port given by the uri
            {
                Console.WriteLine("Started!");
                Console.ReadKey();
                Console.WriteLine("Stopping!");
            }
        }
    }

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Use<HelloWorldComponent>();
        }
    }

    public class HelloWorldComponent
    {
        AppFunc _next;
        public HelloWorldComponent(AppFunc next)
        {
            _next = next;
        }

        // Katana uses reflection to find this Invoke function that matches the AppFunc signature
        public Task Invoke(IDictionary<string, object> environment)
        { 
            var response = environment["owin.ResponseBody"] as Stream;

            using (var writer = new StreamWriter(response))
            {
                return writer.WriteAsync("Hello");
            }
        }
    }
}

packages.config is

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Owin" version="3.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Diagnostics" version="3.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Host.HttpListener" version="3.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Hosting" version="3.0.1" targetFramework="net451" />
  <package id="Owin" version="1.0" targetFramework="net451" />
</packages>

I wonder did not use to get this message, so I wonder what could have changed

Shaun Wilson
  • 8,727
  • 3
  • 50
  • 48
Kirsten
  • 15,730
  • 41
  • 179
  • 318
  • I see some information https://github.com/HangfireIO/Hangfire/issues/242 – Kirsten Apr 22 '15 at 22:32
  • Also https://aspnetwebstack.codeplex.com/workitem/2116 talks about adding binding redirects however mine look like the example – Kirsten Apr 22 '15 at 22:34
  • The code looks 100% correct and I can paste it into a new project and watch it work. Interesting. I don't have any assembly redirects in app.config, though, perhaps you can comment them out and see how it behaves? – OdeToCode Apr 23 '15 at 12:38
  • No difference commenting out the redirects. If I create a new project from scratch I have the same problem. I have tried .net frameworks 4.5 and 4.5.1 – Kirsten Apr 23 '15 at 15:59
  • Odd, feel free to .zip the project and send it along, I'll take a closer look. Email address here: http://odetocode.com/about/contact – OdeToCode Apr 23 '15 at 18:31
  • Thanks Scott, I sent you the email. – Kirsten Apr 23 '15 at 21:42
  • 1
    Ah, the code in the project you send has an Invoke function with an extra Task parameter at the end. Remove that, and all should be good. – OdeToCode Apr 24 '15 at 12:32
  • Ah, thanks Scott, I wonder how on earth I did that! – Kirsten Apr 24 '15 at 19:08
  • I am getting same issue while following this course. But can't figure out how this issue was resolved here. – Manoj Attal Dec 30 '15 at 03:29
  • @Manoj the code above was right at the time, it was a dyslexic mistake on my part that Scott found when I sent him the Zip. Checkout Ufuk-Hacıoğulları 's answer below. – Kirsten Dec 30 '15 at 18:38
  • oh.. ok Thanks @kirsten – Manoj Attal Dec 31 '15 at 04:41

2 Answers2

4

There is a new way to write our middlewares components, which looks like this:

public class HelloWorldComponent : OwinMiddleware
{
    public HelloWorldComponent(OwinMiddleware next) : base(next) { }

    public override Task Invoke(IOwinContext context)
    {
        return context.Response.WriteAsync("Hello, World!");
    }
}

Specifically, the constructor must accept an OwinMiddleware reference as its first parameter, otherwise you get an error because the ctor signature does not match what is expected by the current Owin implementation.

Further, consider the following parameterized usage:

    var param1 = "Hello, World!";
    appBuilder.Use<HelloWorldComponent>(param1)

To properly support this you will want a modified constructor signature:

public class HelloWorldComponent : OwinMiddleware
{
    public HelloWorldComponent(OwinMiddleware next) : base(next) { }

    public override Task Invoke(IOwinContext context, string param1)
    {
        return context.Response.WriteAsync(param1);
    }
}

Thus, allowing us to parameterize our middleware via Use()'s params array.

Shaun Wilson
  • 8,727
  • 3
  • 50
  • 48
Ufuk Hacıoğulları
  • 37,978
  • 12
  • 114
  • 156
  • you sure you've got that right? How can you override a method with a custom parameter? Wouldn't OwinMiddleware base have to supply a ridiculous amount of overloads to permit that? – Quibblesome Dec 28 '16 at 17:23
  • @Quibblesome I think it was an overload with params object[], so it's not safely typed. – Ufuk Hacıoğulları Dec 28 '16 at 18:26
0

Inheriting from OwinMiddleware limits you to the Katana implementation of OWIN.
Creating a OwinContext from the passed environment should work for you

class HelloWorldComponent 
    {
        private readonly AppFunc _next;

        public HelloWorldComponent (AppFunc next)
        {
            _next = next;
        }

        public async Task Invoke(IDictionary<string, object> environment)
        {

            var ctx = new OwinContext(environment);
            await ctx.Response.WriteAsync("Hello World");
            await _next(environment);
        }
    }
Shashank Shekhar
  • 3,958
  • 2
  • 40
  • 52