ASP.NET MVC Application with hosted WCF and Windsor: HttpContext.Current is null - wcf

I've built an ASP.NET MVC 3 Application hosting a WCF-Service. The service class doing the actual work resides within a class library. I'm trying to use the Windsor WCF facility to wire it up on service request.
Here's my Windsor container factory:
public class WindsorContainerFactory
{
private static IWindsorContainer container;
private static readonly object sync = new Object();
public static IWindsorContainer Current()
{
if(container == null) {
lock (sync)
{
if (container == null)
{
container = new WindsorContainer();
container.Install(new ControllerInstaller());
container.Install(new NHibernateSessionInstaller());
container.Install(new RepositoryInstaller());
container.Install(new ServiceInstaller());
}
}
}
return container;
}
}
In Global.asax, I call WindsorContainerFactory.Current() once to guarantee the factory is beeing built:
protected void Application_Start()
{
WindsorContainerFactory.Current();
ControllerBuilder.Current.SetControllerFactory(typeof(WindsorControllerFactory));
...
I install my service by the following class:
public class ServiceInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Kernel.AddFacility<WcfFacility>();
container.Kernel.Register(
Component
.For<ICustomerService>()
.ImplementedBy<CustomerService>()
.Named("CustomerService"));
}
}
Then I added a new WCF service to the project, deleted the code behind file and modified the svc markup as follows:
<%# ServiceHost Language="C#" Debug="true"
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory,
Castle.Facilities.WcfIntegration" Service="CustomerService" %>
As you can see, there are other components beeing installed within windsor (Repositories, Controllers,...), but this seems to work well.
My problem is, that the WCF-client (console app) gets the error:
HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net
Client code:
CustomerServiceClient c = new Services.Customers.CustomerServiceClient();
CustomerResponse resp = c.GetCustomerBySurname("Lolman");
c.Close();
Can anyone point me to the right direction?
Thank you in advance!

Try enabling AspNetCompatibility.
Check this link for help

Related

Self-Hostable and IIS-hostable OWIN project

I would like to modify my solution to run under a self-hosted OWIN instance, but I also need it to run under http://localhost when necessary.
How should I structure my Startup class to be recognised by both?
Currently, I have the Web API project set as a Console Application with the project URL as http://localhost:2746 and this is my Startup class:
[assembly: OwinStartup(typeof(Startup))]
namespace Books
{
public class Startup
{
public static void Main(string[] args)
{
const int port = 2746;
var url = $"http://localhost:{port}/";
using (WebApp.Start<Startup>(new StartOptions(url) { ServerFactory = "Microsoft.Owin.Host.HttpListener" }))
{
var client = new HttpClient { BaseAddress = new Uri(url) };
Console.ReadLine();
}
}
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfiguration = new HttpConfiguration();
WebApiConfig.Register(httpConfiguration);
app.Use<CustomExceptionMiddleware>().UseWebApi(httpConfiguration);
app.UseFileServer(StaticFileConfig.Build());
}
}
}
I also have this in the web.config:
<add key="owin:AutomaticAppStartup" value="false" />
use two projects:
create a web project for the api controllers. this project can host in iis
create another console project as the self-host, this project need refer the web project, now you can share the WebApiConfig/Controllers to this project
ps: OwinStartup attribute indicate the entrypoint for iis, but i use the traditional global.asax to initial the api config. so that the Startup class can also share the config from WebApiConfig

AspNet Core 1.1 Inject IOptions into a class

I am using the Options pattern in my AspNet Core 1.1 application. Everything is set according to the documentation:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<AppOptions>(Configuration);
...
}
I would like to inject the AppOptions class into a service that I am creating:
public class MyService
{
private readonly AppOptions options;
public MyService(IOptions<AppOptions> optionsAssesor)
{
options = optionsAssesor.Value;
}
...
}
My questions is: when I try to create an instance of the MyService class like:
MyService svc = new MyService();
I am getting an error saying that There is no argument given that corresponds to the required formal parameter optionsAssesor How can I take advantage of the DI and inject the AppOptions into my service?
I am kind of new to .NET Core so I am guessing I am missing something simple, but I cannot figure out what.
Thank you.
I am assuming that Service (MyService) is within scope of ASP.net core project.
You have to do following Thing.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<MyService>();
... other things
}
Now Suppose that you are using your service ( or you want to use your service some controller then you have to do
public class HomeController : Controller
{
private MyService _myService = null;
public HomeController(MyService service)
{
_myService = service;
}
// now you can use _myService in your controller method.
}
Every thing like you have to go through Dependency.
Update 1
Now suppose you want to use it in another class then you can do like this.
For example another class is MyClass1.
public class MyClass1
{
private MyService _myService = null;
public MyClass1(MyService service)
{
_myService = service;
}
}
Now if I am thinking correct then if you are using ASP.net core then MyClass1 one way or other it will use by Controller. You have to register dependency for this.
services.AddScoped<MyClass1>(); // This should be in your ConfigureServices.
It depends on where you are trying to get an instance of MyService from. Basically you need to get a reference to the services collection (and register MyService in DI as well in startup), build a service provider, and then get the service. This will allow DI to construct an instance of MyService and pass it in an instance of AppOptions.
For example:
var provider = serviceCollection.BuildServiceProvider();
var myService = provider.GetService<MyService>();
That being said, in most places in ASP.NET Core you don't need to do this and are better off getting an instance of MyService through the Controller / Middleware constructor without having to build a Service Provider on your own.
You should look at the Microsoft Docs on Dependency Injection in ASP.NET core to further understand the different Service Lifetimes.

Nservicebus 5 and later Web Api Depenedency Injection settings

How can I configure Web api dependency settings for NserviceBus 5 and later version.
Version 3 or 4 is like this:
public static class ConfigureWebApi
{
public static Configure ForWebApi(this Configure configure)
{
// Register our http controller activator with NSB
configure.Configurer.RegisterSingleton(typeof(IHttpControllerActivator),
new NSBHttpControllerActivator());
// Find every http controller class so that we can register it
var controllers = Configure.TypesToScan
.Where(t => typeof(IHttpController).IsAssignableFrom(t));
// Register each http controller class with the NServiceBus container
foreach (Type type in controllers)
configure.Configurer.ConfigureComponent(type, ComponentCallModelEnum.Singlecall);
// Set the WebApi dependency resolver to use our resolver
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NServiceBusResolverAdapter(configure.Builder));
// Required by the fluent configuration semantics
return configure;
}
}
But Version 5 does not use Configure class, that use BusConfiguration
I try this but can not scan assemblies:
public static class ConfigureWebApi
{
public static BusConfiguration ForWebApi(this BusConfiguration configuration)
{
configuration.RegisterComponents(c => c.RegisterSingleton(typeof(IHttpControllerActivator),
new NServiceBusHttpControllerActivator()));
????
}
}
I'm not sure which way you're thinking. I'm asking, because I might be wrong with my answer. If so, let me know and I'll try to update it.
The way I go about this issue is setting up the container first and then have NServiceBus use that container. I'm using AutoFac and create a special class to set it up.
Disclaimer : I'm copying this from an existing app and didn't try nor compile it. I'm 100% sure this is working though, although I might've forgotten a line or added one too much! :)
public class DependenciesConfig
{
public static IContainer RegisterDependencies()
{
ContainerBuilder builder = new ContainerBuilder();
// MVC Controllers
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterControllers(Assembly.GetExecutingAssembly())
// WebAPI controllers
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
// Way more registrations
// Next line is AutoFac specific for WebAPI
builder.RegisterFilterProvider();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
return container;
}
}
Then I have an additional class for registering NServiceBus. I don't have handlers in my web app, nor do I publish messages, so I use a SendOnly endpoint.
public class ServiceBus
{
public static ISendOnlyBus Bus { get; private set; }
private static readonly object padlock = new object();
public static void Init(ILifetimeScope container)
{
if (Bus != null) return;
NServiceBus.Logging.LogManager.Use<CommonLoggingFactory>();
lock (padlock)
{
if (Bus != null) return;
var configuration = new BusConfiguration();
configuration.UseSerialization<JsonSerializer>();
configuration.UseContainer<AutofacBuilder>(x => x.ExistingLifetimeScope(container));
configuration.UseTransport<AzureStorageQueueTransport>();
ConventionsBuilder conventions = configuration.Conventions();
conventions.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.StartsWith("Messages") && t.Namespace.EndsWith("Commands"));
Bus = NServiceBus.Bus.CreateSendOnly(configuration);
}
}
}
Is this what you're looking for?

How to use Autofac with a CustomServiceHostFactory in an IIS hosted WCF service?

Lets say I have a simple service contract:
[ServiceContract(Namespace = Constants.MyNamespace)]
public interface IAccountService
{
[OperationContract]
Account GetByAccountNumber(string accountNumber);
}
Here is the service:
[ServiceBehavior(Namespace = Constants.MyNamespace)]
public class AccountService : IAccountService
{
private readonly IUnitOfWorkAsync _uow;
private readonly IRepositoryAsync<Account> _repository;
public AccountService(IDataContextAsync dataContext)
{
_uow = new UnitOfWork(dataContext);
_repository = new Repository<Account>(dataContext, _uow);
}
public Account GetByAccountNumber(string accountNumber)
{
return _repository.GetByAccountNumber(accountNumber);
}
}
Here is the CustomServiceHostFactory:
public class CustomServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
builder.Register(c => new AccountService(c.Resolve<IDataContextAsync>())).As<IAccountService>();
using (var container = builder.Build())
{
var host = new CustomServiceHost(serviceType, baseAddresses);
host.AddDependencyInjectionBehavior<IAccountService>(container);
return host;
}
}
}
..where CustomServiceHost creates all of the bindings/behaviors programmatically. I am using file-less activation so my .config file just has section like this:
<serviceHostingEnvironment>
<serviceActivations>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="Account/AccountService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
I publish to IIS and can view the site in a browser. It says "you have created a service". However, any call I try to make to the service from my client application gives the following error:
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
How do you use Autofac with WCF and a CustomServiceHostFactory?
I am able to use poor man's DI as a workaround for now but was hoping to get this working. I can't seem to find any good examples on the web. Thanks.
Don't dispose of the container. Instead of a using statement, keep the container alive. It needs to live as long as the host.
You'll notice in the default Autofac WCF stuff the container is a global static that lives for the app lifetime - that's why.

Ninject for Asp.net Web API

I got this error when using Ninject with Web API, but it works with MVC Controller:
Type 'App.Web.Controllers.ProductController' does not have a default constructor
NinjectControllerFactory :
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
}
public void AddBindings()
{
ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();
}
}
Global.asax.cs :
BundleConfig.RegisterBundles(BundleTable.Bundles);
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
ProductController :
public class ProductController : ApiController
{
private IProductRepository repository;
public ProductController(IProductRepository ProducteRepository)
{
this.repository = ProductRepository;
}
public IEnumerable<Product> GetAllProducts()
{
return repository.Products.AsEnumerable();
}
}
You have overriden the DefaultControllerFactory. But this is used to instantiate ASP.NET MVC controllers (one deriving from System.Web.Mvc.Controller). It has strictly nothing to do with ASP.NET Web API controllers (the ones deriving from System.Web.Http.ApiController).
So basically what you have done here is dependency injection into ASP.NET MVC. If you want to use this for the Web API you may take a look at the following guides:
http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
You should use the latest Ninject Web API package, which solves these problems already. See here: http://nuget.org/packages/Ninject.Web.WebApi.WebHost/
You need to set DependencyResolver property of the HttpConfiguration. What you have done was for ASP.NET MVC and not ASP.NET Web API.
So get the NuGet package and set DependencyResolver:
var kernel = new StandardKernel();
// use kernel to register your dependencies
var dependencyResolver = new NInjectResolver(kernel);
config.DependencyResolver = dependencyResolver; // config is an instance of HttpConfiguration based on your hosting scenario