ASP.NET Web Api 2, Ninject, OWIN, and IIS - iis

I'm using Ninject for dependency injection in my ASP.NET Web Api 2 project. Everything is working perfectly locally through Visual Studio and IIS Express, but when I deploy to IIS, the dependency's are not resolved. Below is my Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
webApiConfiguration.EnableCors();
webApiConfiguration.SuppressDefaultHostAuthentication();
webApiConfiguration.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
webApiConfiguration.MapHttpAttributeRoutes();
app.UseNinjectMiddleware(CreateKernel).UseNinjectWebApi(webApiConfiguration);
ConfigureAuth(app);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
app.Run(async context =>
{
await context.Response.WriteAsync("Welcome to Web API");
});
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Load(new CourseModule(), new DataPullModule(), new DegreeModule(), new ResponseModule(), new RestSharpModule());
return kernel;
}
}
The error I get is when trying to access one of my controllers is below:
An error occurred when trying to create a controller of type 'DegreeController'. Make sure that the controller has a parameterless public constructor.
Here is my constructor for the DegreeController:
public DegreeController(IDegreeMapper degreeMapper, IDegreeRepository degreeRepository)
{
_degreeMapper = degreeMapper;
_degreeRepository = degreeRepository;
}
And here is the DegreeModule where I bind interfaces to classes.
public class DegreeModule : NinjectModule
{
public override void Load()
{
Bind<IDegreeController>().To<DegreeController>().InRequestScope();
Bind<IDegreeMapper>().To<DegreeMapper>().InRequestScope();
Bind<IDegreeRepository>().To<DegreeRepository>().InRequestScope();
Bind<IDegreeRatingCalculator>().To<DegreeRatingCalculator>().InRequestScope();
}
}

var kernel = CreateKernel();
app.UseNinjectMiddleware(() => kernel).UseNinjectWebApi(configuration);

Related

Autofac interceptor not working for some classes

I have to do some extra logic layer on existing classes. I'm using autofac.
The project is Windows service having also Kestrel server. Program.cs e.g.
void Main(string[] args) {
var customQueue = new CustomQueue();
var someClass = new SomeClass(customQueue);
var randomClass = new RandomClass();
// do some logic here with using declared instances
var server = new Server(someClass, randomClass);
server.Start();
}
And here is the Server.cs
class Server {
private IWebHost _host;
public Server(SomeClass cls, RandomClass cls1) {
// set to fields
}
void Start() {
_host = new WebHostBuilder()
.UseKestrel()
.ConfigureServices(services =>
{
services.AddAutoFac(); // first as per doc in order to scaffold 'ConfigureContainer'?
services.AddSingleton(someClass); // fields
services.AddSingleton(randomClass); // fields
})
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration(...)
.ConfigureLogging(...);
.UseStartup<Startuo>()
.Build();
_host.StartAsync();
}
}
Startup.cs
public class Startup
{
public ILifetimeScope AutofacContainer { get; private set; }
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// create a container-builder and register dependencies
var builder = new ContainerBuilder();
// populate the service-descriptors added to `IServiceCollection`
// BEFORE you add things to Autofac so that the Autofac
// registrations can override stuff in the `IServiceCollection`
// as needed
builder.Populate(services);
builder.RegisterType<SomeClass>()
.As<ISomeClass>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(SomeClassInterceptor));
builder.Register(_ => new SomeClassInterceptor());
AutofacContainer = builder.Build();
return new AutofacServiceProvider(AutofacContainer);
}
}
And last SomeClassInterceptor.cs
public class SomeClassInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
if (invocation.ReturnValue is Task taskResult)
{
taskResult.ContinueWith(
t =>
{
Console.WriteLine("OOHH YEAHH");
}, TaskContinuationOptions.None);
}
else
{
Console.WriteLine("WOW");
}
}
catch (Exception ex)
{
Console.WriteLine("EXCEPTIOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNN");
}
}
}
I've tried with Named and Typed registration with having Intercept(...) attribute but still no success. Nothing gets triggered.
Also ISomeClass is inheriting other interfaces, I've tried setting .As<>() also with those but no.
What am I missing?
In order to let the interceptor works. The class should be build by Autofac.
services.AddAutofac();
services.AddSingleton(someClass);
services.AddSingleton(randomClass);
In your case you configure Autofac using the AddAutofac method then add SomeClass as a singleton using the AddSingleton which will override the Autofac configuration. There is no way that Autofac can inject the interceptor in it.
If you want to register SomeClass as singleton you should register it using the SingleInstance() method
builder.RegisterType<SomeClass>()
.As<ISomeClass>()
.SingleInstance()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(SomeClassInterceptor));

Configure AutoMapper using LightInject

Does anyone know how to configure AutoMapper using LightInject? The AutoMapper documentation only has examples for Ninject and Simple Injector.
I am having difficulty trying to register the AutoMapper configuration.
I'm using ASP.NET MVC C#.
public class CompositionRoot : ICompositionRoot
{
public void Compose(IServiceRegistry serviceRegistry)
{
serviceRegistry.Register(c => new AutoMapperConfiguration());
}
}
public static class AutoMapperConfiguration
{
public AutoMapperConfiguration()
{
Mapper.Initialize(cfg =>
cfg.AddProfiles(typeof(Namespace.Class).Assembly)
);
}
}
I figured it out. The code below is in the CompositionRoot, where the factory is registered using IServiceRegistry. I will be moving the var config = new MapperConfiguration(cfg => cfg.AddProfiles(typeof(CustomProfileClass).Assembly)); code to a custom MapperConfiguration class that I will create.
public class CompositionRoot : ICompositionRoot
{
public void Compose(IServiceRegistry serviceRegistry)
{
var config = new MapperConfiguration(cfg => cfg.AddProfiles(typeof(CustomProfileClass)));
serviceRegistry.Register(c => config.CreateMapper());
}
}

404 /signalr/negotiate for deployed app in Azure

SignalR works on localhost but doesn't work when is deployed in Azure
Asp.net Core 1.0.0 (.Net Framework 4.6.1)
SignalR.Core 2.2.1
public static void UseSignalR2(this IApplicationBuilder app)
{
app.UseAppBuilder(appBuilder => {
appBuilder.MapSignalR(new HubConfiguration());
});
GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule());
GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());
}
SignalR.js 2.2.1 with default settings
$.connection.hub.url = '/signalr';
Expected behavior
200 for url:
https://(name).azurewebsites.com/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22productsimporthub%22%7D%5D&_=1472811629592
Actual behavior
/signalr/negotiate - on localhost returns 200 but for deployed app in azure returns 404
/signalr - works on both - Protocol error: Unknown transport.
/signalr/hubs - works on both - returns the SignalR js correctly
To find out the real cause of the issue you need to navigate to the negotiate url, and look for the response.
If the response tells you something about a 'CryptographicException: The data protection operation was unsuccessful...'. This is how to fix it.
1) Create a custom IDataProtectionProvider
2) Configure signalr
internal class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
internal class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
//return MachineKey.Protect(userData, _purposes);
return userData;
}
public byte[] Unprotect(byte[] protectedData)
{
//return System.Web.Security.MachineKey.Unprotect(protectedData, _purposes);
return protectedData;
}
}
I use katana extension methods to bridge the IAppBuilder to IApplicationBuilder.
This allows your owin middleware to connect to asp.net core. It is important to use the RunSignalr method
app.UseAppBuilder(appBuilder =>
{
appBuilder.SetDataProtectionProvider(new MachineKeyProtectionProvider());
appBuilder.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true
};
map.RunSignalR(hubConfiguration);
});
});

Combine azure mobile service autofac with nservicebus registrations

I am trying to combine the registrations of the azure mobile service and the nservicebus registrations. When i try to inject the IBus into an controller it doesn't work.
public class AutofacConfig
{
public static void Register(HttpConfiguration http, ContainerBuilder container)
{
var busConfiguration = new BusConfiguration();
busConfiguration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container.Build()));
var bus = Bus.Create(busConfiguration);
bus.Start();
}
}
I need to call container.Build() in order to pass the current container to NServiceBus. but this results in an error in ServiceConfig.Initialize in my WebApiConfig class
public static class WebApiConfig
{
public static void Register()
{
// Use this class to set configuration options for your mobile service
ConfigOptions options = new ConfigOptions();
// Use this class to set WebAPI configuration options
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options, AutofacConfig.Register));
// To display errors in the browser during development, uncomment the following
// line. Comment it out again when you deploy your service for production use.
// config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Database.SetInitializer(new nos_devInitializer());
}
}
Ok, i see i can resolve the ILifetimeScope from the dependencyresolver. Call this method after ServiceConfig.Initialize and the two registrations are paired.
public class NServiceBusConfig
{
public static void Register(HttpConfiguration config)
{
var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
var scope = resolver.GetService<ILifetimeScope>();
var busConfiguration = new BusConfiguration();
busConfiguration.UseContainer<AutofacBuilder>(f => f.ExistingLifetimeScope(scope));
var bus = Bus.Create(busConfiguration);
bus.Start();
}
}

How can I instantiate OWIN IDataProtectionProvider in Azure Web Jobs?

I need an instance of IDataProtectionProvider to generate email confirmation tokens using the Identity Framework UserManager in an Azure Web Jobs worker:
var confirmToken = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
This crashes because a null IUserTokenProvider<User, int> was passed to the UserManager<User, int> upon constuction.
In the MVC application an instance is created like this:
public class OWINStartup
{
public void Configuration(IAppBuilder app)
{
var dataProtectionProvider = app.GetDataProtectionProvider();
But of course, Azure Web Jobs doesn't have an OWINStartup hook. Any advice?
Taking a look at the Katana source code for the OWIN startup context you can see the default implementation of the DataProtectionProvider is a MachineKeyDataProtectionProvider. Unfortunately this class is not exposed to us, only the DpapiDataProtectionProvider which will not work when hosted in azure.
You can find the implementation of the MachineKeyDataProtectionProvider here. You will need to also implement your own MachineKeyDataProtector as seen here. These are not difficult implmentations and are essentially wrappers around MachineKey.Protect() and MachineKey.Unprotect().
The implementation for MachineKeyDataProtectionProvider and MachineKeyDataProtector from the Katana project source (apache 2.0 license):
internal class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
internal class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, _purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, _purposes);
}
}
Once you have that implemented it is easy to plug into the UserManager:
var usermanager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>());
var machineKeyProtectionProvider = new MachineKeyProtectionProvider();
usermanager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(machineKeyProtectionProvider.Create("ASP.NET Identity"));
Hope that helps get you in the right direction.

Resources