Autofac WCF integration + sessions - wcf

I am having an ASP.NET MVC 3 application that collaborates with a WCF service, which is hosted using Autofac host factory. Here are some code samples:
.svc file:
<%# ServiceHost
Language="C#"
Debug="true"
Service="MyNamespace.IMyContract, MyAssembly"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
Global.asax of the WCF service project:
protected void Application_Start(object sender, EventArgs e)
{
ContainerBuilder builder = new ContainerBuilder();
//Here I perform all registrations, including implementation of IMyContract
AutofacServiceHostFactory.Container = builder.Build();
}
Client proxy class constructor (MVC side):
ContainerBuilder builder = new ContainerBuilder();
builder.Register(c => new ChannelFactory<IMyContract>(
new BasicHttpBinding(),
new EndpointAddress(Settings.Default.Url_MyService)))
.SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<IMyContract>>().CreateChannel())
.UseWcfSafeRelease();
_container = builder.Build();
This works fine until I want WCF service to allow or require sessions ([ServiceContract(SessionMode = SessionMode.Allowed)], or [ServiceContract(SessionMode = SessionMode.Required)]) and to share one session with the MVC side. I changed the binding to WSHttpBinding on the MVC side, but I am having different exceptions depending on how I tune it.
I also tried changing AutofacServiceHostFactory to AutofacWebServiceHostFactory, with no result.
I am not using config file as I am mainly experimenting, not developing real-life application, but I need to study the case. But if you think I can achieve what I need only with config files, then OK, I'll use them.
I will provide exception details for each combination of settings if required, I'm omitting them not to make the post too large. Any ideas on what I can do?

Related

Integration Testing Minimal API .NET 6 - nUnit

With .NET 5 I used the following in my nUnit [SetUp] for each test. This created a host and a client with which I could call my API with full integrations as defined in the Startup:
Microsoft.AspNetCore.TestHost.TestServer _testServer;
HttpClient _testClient;
[SetUp]
public async Task SetUp()
{
// Load up test configuration
IConfiguration config = new ConfigurationBuilder()
.SetBasePath("mypath")
.AddJsonFile("integrationsettings.json")
.Build();
// Create the host (using startup)
WebHostBuilder builder = new WebHostBuilder()
// Use startup from WebApp Server project
.UserStartup<MyWebApp.Startup>()
// Configure logging from integrationsettings.json
.ConfigureLogging((hostingContext, logging) =>
logging.AddConfiguration(config.GetSection("Logging"))
// Set core app configuration to use integrationsettings.json
.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(config))
// Add any additional services not loaded by startup
.ConfigureServices(services => // add additional services not laoded in Startup);
// Create the Server
_testServer = new TestServer(builder);
// Create the Client
_testClient = _testServer.CreateClient();
}
I could then use testClient HttpClient to work directly with my API.
Life was sweet.
I know I could still use the old model with .NET 6 (Program.cs + Startup.cs), but if I'm going to go with the flow, now that we have minimal API with just the Program.cs, how do I replicate the above?
From what I can gather, it looks like WebApplicationFactory is the key, but have not found anything that gets me over the line.
Is it as simple as adding the assembly that contains WebApplication and just build the app in test SetUp in the same way as I do in Program.cs on the server?
Is there a way to encapsulate the build logic (much like the old Startup.cs) so I do not need to duplicate the configuration used on the server in my tests?

ConnectionString from appsettings.json in Data Tier with Entity Framework Core

I have a new application that I am building on ASP.NET Core with Entity Framework Core. The application has a UI, model, business, and data tier. In previous versions of ASP.NET, you could set the connection string in the web.config and it would be available in referenced tiers by default. This does not appear to be the same case in ASP.NET Core with appsettings.json (or other config options)? Any idea on how this is accomplished? I have the dbcontext configured in the data layer, but I am current hard-coding the connection string.
All examples I have see out there has the dbcontext configured in the UI layer in startup.cs. This is what I am trying to avoid.
The question Here got off topic.
You can easily add an extension method of IServiceCollection into your business/services layer and use it to register its own dependencies. Then in the startup you just call the method on the service layer without having any reference to EntityFramework in your web app.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace your.service.layer
{
public static class MyServiceCollectionExtensions
{
public static IServiceCollection AddMyServiceDependencies(this IServiceCollection services, string connectionString)
{
services.AddEntityFrameworkSqlServer()
.AddDbContext<YourDbContext>((serviceProvider, options) =>
options.UseSqlServer(connectionString)
.UseInternalServiceProvider(serviceProvider)
);
return services;
}
}
}
Startup:
using your.service.layer;
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("EntityFrameworkConnectionString");
services.AddMyServiceDependencies(connectionString);
}
Now your web app only needs a reference to your business/service layer and it is not directly dependent on EntityFramework.

Autofac returns different instance in asp.net mvc web api

I'm using autofac in an asp.net mvc and webapi project.
In the configuration I'm doing this :
var builder = new ContainerBuilder();
builder.Register(x => NHibernateConfigurator.BuildSessionFactory()).SingleInstance();
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerHttpRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
Now the problem is that in an api controller if I inject ISession via the constructer and also call
DependencyResolver.Current.GetService<ISession>()
it will return 2 different instances.
I'm guessing the problem is because of these 2 lines :
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
But how can I make it return the same instance ?
Edit:
Just to be more clear - I'm expecting the same instance of ISession per HttpRequest. Right now I'm getting different instances on the same request.
Thanks
Ok, I think I found the answer - it can't be done .. at least not with DependencyResolver.
ASP .Net 4 Web Api RC + Autofac manual resolving
I did what it said in the comments, added IComponentContext to the constructor and used that to resolve what I needed.
It seems to be working. Thanks.

Configuring a WCF and StructureMap ServiceHostFactory from code

I am creating a custom ServiceHost object and configuring it from code. My service is using InstanceContextMode.Single and ConcurrencyMode.Multiple and is hosted in a windows service.
As stated in a number of blogs/articles (here), sharing a StructureMap container across instances requires using a custom InstanceProvider, ServiceBehavior and ServiceHostFactory.
My initialization code looks like this. I do not use a config file.
var baseAddress = ConfigurationManager.AppSettings["BaseAddress"];
var port = Int32.Parse(ConfigurationManager.AppSettings["Port"]);
Host = new MyServiceHost(typeof(MediaFileServicePrivate), new Uri(string.Format(baseAddress, port)));
var binding = new NetTcpBinding();
Host.AddServiceEndpoint(typeof(IMediaFileServicePrivate), binding, string.Format(baseAddress, port));
How do I tell the service to use my custom service host factory? All the examples I can find configure it from the config file.
Is a ServiceHostFactory only used for IIS/WAS hosted scenarios? If so, how do I use SM for a self-hosted InstanceContextMode.Single service?
Has this not been answered? essentially you tell it to use your servicefactory in the wcf markup
<%# ServiceHost Language="C#" Debug="true" Service="WcfWithDI.Service1" CodeBehind="Service1.svc.cs" Factory="WcfWithDI.MyServiceFactory"%>
I have a sample project here all wired up with a custom provider (and structuremap)
https://github.com/billCreativeD/WCF_With_DI
Unfortunately it makes little sense to say "the service uses the factory". You would use the Ninject factory to create your service:
var factory = new NinjectServiceHostFactory();
var address = new Uri(_baseAddress, path);
ServiceHostBase host = factory.CreateServiceHost(typeName, new[] {address});
var binding = new NetTcpBinding();
host.AddServiceEndpoint(typeof(TheType), binding, string.Format(baseAddress, port));
The directive in the .svc file is used to tell .NET how to instantiate your service.

Problem creating WCF service with Windsor

Does anyone know how to configure WCF using Windsor on IIS 7.0? I'm using the latest from WCF Windsor facility trunk and Windsor 2.1.1. The example on http://www.castleproject.org/container/facilities/trunk/wcf/index.html is out of date. Even demo project in WCF facility doesn't mention how to setup WCF service in IIS using the config and I couldn't find any example where I can setup WCF on server side using system.serviceModel section of web.config or even through code. When I use the following code it always creates basicHttpBinding and I couldn't figure out how to setup different bindings.
protected void Application_Start(object sender, EventArgs e)
{
var returnFaults = new ServiceDebugBehavior
{
IncludeExceptionDetailInFaults = true,
HttpHelpPageEnabled = true
};
var metadata = new ServiceMetadataBehavior {HttpGetEnabled = true};
container = new WindsorContainer()
.AddFacility<WcfFacility>()
.Register(
Component.For<IServiceBehavior>().Instance(returnFaults),
Component.For<IServiceBehavior>().Instance(metadata),
Component.For<IMyService>()
.Named("MyService")
.ImplementedBy<MyService>()
.LifeStyle.Transient
);
}
And here is MyService.svc
<%# ServiceHost Language="C#" Debug="true" Service="MyService"
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" %>
I recently wrote a blog post about Windsor's WCF Facility. Be sure to read the comments as well, as they include a discussion involving one of Windsor's active committers; they should give you a pretty good impression of the future direction.