WCF IServiceBehavior - wcf

I have a ServiceBehavior Attribute like this:
AdhocAuthenticationAndAuthorisation : IServiceBehavior
{
public AdhocAuthenticationAndAuthorisation(string systemName, string serviceName)
{
//Some code here.
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
//+ Other interface members.
}
This is used for some authentication and authorisation, the Attribute is used to bootstrap some context information that is used later, the context is set up in the Validate method, and works fine when i only use the Attribute on one service in the same apppool. However on a second service(different service interface) in the same apppool the Validate method of the second Attribute is never run if i instantiate the second service, at the same time. If I instantiate the first service and wait 5 seconds and instantiate the other, then the validate method is called.
This has been tested on different bindings and with aspNetCompatibilityEnabled = on or off. The services run on .net and iis 7.5
Does any one know how to solve this issue?

Related

Instantiating IHubContext in ASP.NET Core

I am using SignalR on different places of my web project. In my Controllers and HostedService this seems to be working fine. Clients instantiate connections with my hub and I can communicate with them back using an IHubContext instance, injected in the constructor of every controller/hostedservice.
I am having another singleton, running in Background (No HosteService or BackgroundTask). This class is getting IHubContext injected in the constructor also. Still every time it gets called, it seems like this singleton is having a different instance of IHubContext, since this context has no clients/groups connected to it.
This class is being registered as this in the startup function:
services.AddSingleton<IServiceEventHandler<TourMonitorEvent>, TourMonitorEventHandler>();
To configure SignalR I am doing the following in ConfigureServices:
services.AddSignalR().AddNewtonsoftJsonProtocol();
and the following in configure:
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<MyHubClass>("/hubEndpoint");
endpoints.MapControllers();
});
the IHubContext ist bein injected as following in both Controllers/Hostedservices and the singleton:
public class MySingleton : IHandler<SomeGenericClass>
{
private readonly IHubContext<MyHubClass> _hubContext;
public MySingleton(IHubContext<MyHubClass> hubContext)
{
_hubContext = hubContext;
}
}
Are Controllers/HosteService being instantiated differently than my Singleton, in a way that might affect IHubContext instantiation?
As said in the documentation:
Hubs are transient.
So since you Singleton is not a HostedService or a BackgroundTask, I would recomend to inject the hub using a DI.
private IHubContext<MyHubClass, IMyHubClass> MyHubClass
{
get
{
return this.serviceProvider.GetRequiredService<IHubContext<MyHubClass, IMyHubClass>>();
}
}
Try this and verify if the context now is as you expected.

Resolving dependencies in Integration test in ASP.NET Core

I have ASP.NET Core API. I have already gone through documentation here that shows how to do integration testing in asp.net core. The example sets up a test server and then invoke controller method.
However I want to test a particular class method directly (not a controller method)? For example:
public class MyService : IMyService
{
private readonly DbContext _dbContext;
public MyService(DbContext dbContext)
{
_dbContext = dbContext;
}
public void DoSomething()
{
//do something here
}
}
When the test starts I want startup.cs to be called so all the dependencies will get register. (like dbcontext) but I am not sure in integration test how do I resolve IMyService?
Note: The reason I want to test DoSomething() method directly because this method will not get invoked by any controller. I am using Hangfire inside this API for background processing. The Hangfire's background processing job will call DoSomething() method. So for integration test I want to avoid using Hangfire and just directly call DoSomething() method
You already have a TestServer when you run integration tests, from here you can easily access the application wide container. You can't access the RequestServices for obvious reason (it's only available in HttpContext, which is created once per request).
var testServer = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment("DevelopmentOrTestingOrWhateverElse"));
var myService = testServer.Host.Services.GetRequiredService<IMyService>();

Global.asax's Application_Start method doesn't get called

I have a WCF web service hosted on my Local IIS (not Express). I've included a Global.asax in its root directory, where it is supposed to be. Since I'm using Ninject with WCF extensions, the class Global extends NinjectHttpApplication instead of HttpApplication (as seen here).
Also, I'm using the AutoMapper library in order to circumvent writing boring boilerplate code.
The problem arises because a static method I defined for configuring AutoMapper isn't being called causing AutoMapper to throw exceptions when I call Mapper.Map(). That static method's call is defined in Global.asax's Application_Start() method since I want these mappings to be performed once per the web service's lifetime.
Ninject's CreateKernel() method gets called just fine, by the way.
Am I missing something here? I've tried debugging it, it doesn't hit the breakpoint even though I've attached the debugger to w3wp.exe and also tried putting an explicit Debugger.Break() call in its body.
This is how it looks like so far:
Global.asax
<%# Application Codebehind="Global.asax.cs" Inherits="MyApp.WebHost.Global" Language="C#" %>
Global.asax.cs
public class Global : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
IKernel kernel = new StandardKernel();
/* various bindings */
return kernel;
}
protected void Application_Start(object sender, EventArgs e)
{
AutoMapperConfig.RegisterMappings();
}
/* rest of Global.asax methods (Session_Start, Application_BeginRequest, etc.) with empty bodies */
RegisterMappings method
public static class AutoMapperConfig
{
public static void RegisterMappings()
{
/* multiple calls to Mapper.CreateMap() */
Mapper.AssertConfigurationIsValid();
}
}
Svc file markup
<%# ServiceHost Language="C#"
Debug="true"
Service="MyApp.Services.MyAppService"
Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>
Everything else works, I've already created a test client (a simple console app) and added a service reference. Service methods get called just fine, it is just that these mappings are a bit problematic since AutoMapper keeps throwing AutoMapperMappingException exceptions ("Missing type map configuration or unsupported mapping.") for the obvious reasons.
The application's app pool is DefaultAppPool. Should I create a separate one?
I really don't understand the problem here. Thank you in advance.
Well, it required some additional searching but I found the answer here - https://groups.google.com/forum/#!topic/ninject/wRy3ELSV4bU
The problem was that NinjectHttpApplication class itself implements the Application_Startup method so it is impossible to implement it in your own derived class (Global class).
To simulate such behavior one needs to override the OnApplicationStarted Ninject's method.
This is how it looks like regarding my particular problem:
protected override void OnApplicationStarted()
{
AutoMapperConfig.RegisterMappings();
}

WCF Extensibility – IInstanceProvider in mono

I followed : this article and implemented it in a WCF Service.
It allows us to create a instance of a Service that doesn't have a parameterless constructor, by implementing a custom IServiceBehavior, and then decorating the service with that Service Behavior, so instead of having for example:
[ServiceBehavior]
public class MyService : IMyService
I would have
[InstanceProviderBehavior]
public class MyService : IMyService
I then implement the ApplyDispatchBehavior like this:
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers) {
foreach (EndpointDispatcher ed in cd.Endpoints) {
if (!ed.IsSystemEndpoint) {
Console.WriteLine("Using InstanceProviderBehaviorAttribute");
ed.DispatchRuntime.InstanceProvider = new ServiceInstanceProvider(Configuration.Instance.Container);
}
}
}
And to provide an instance of the service I just do:
public object GetInstance(InstanceContext instanceContext, Message message)
{
AlertQueryService result = Container.Resolve<AlertQueryService>();
return result;
}
I ran it in windows and it worked as expected. But in linux with mono, it throws the exception
Exception Default constructor not found for type MyService
which indicates that maybe mono is ignoring the InstanceProviderBehaviorAttribute.
Another thing i noticed was that the line:
Console.WriteLine("Using InstanceProviderBehaviorAttribute");
Is executed in windows when the service host is opened. While in linux when the service host is opened, it doesn't write that in the console. Also the exception in linux is not thrown when we open the service host, but when the IsInitiating operation is called in MyService:
[OperationContract(IsInitiating = true)]
void Initialize();
Which indicates that with mono the service instance is only being resolved when we call the IsInitiating operation.
Any idea why this is works in windows and not in linux with mono? And why is the initialization behavior different?
Thanks
Try adding an InstanceContextProvider as well as your InstanceProvider in your EndpointBehavior. It seems the Mono implementation of ChannelDispatcher.ListenerLoopManager.Setup doesn't like the idea of being sans InstanceContextProvider if there is no parameterless constructor.
The InstanceContextProvider can be essentially a no-op implementation. So long as there is an instance, it will pass that check in ListenerLoopManagerSetup and happily proceed to utilize your InstanceProvider.
Re: why the different implementation... Mono is a re-implementation rather than a cross-compilation or even port. Consider the Important Rules section of their Contribution Guidelines. It wasn't until very recently that developers could contribute to the project if they had so much as looked at MS source code.

Castle WCF Facility, Use of generic interface for non generic contract

I tried to minimize writing of code for WCF CRUD part of big project with use of generics and castle WCF facility.
I have WCF service contract:
[ServiceContract]
public interface IResourceService : ICRUDService<DTOResource>
{
[OperationContract]
DTOResource Get(long id);
}
and generic interface
public interface ICRUDService<T> where T is IDTO
{
T Get(long id);
}
also generic MVC controller (1 controller for all basic crud for dtos and services)
public class CRUDController<T> : Controller where T is IDTO
{
readonly ICRUDService<T> service;
public CRUDController(ICRUDService<T> service)
{
this.service = service;
}
}
On the client side i register WCF client in Windsor Container
Component
.For<IResourceService , ICRUDService<DTOResource>>()
.AsWcfClient(... standard stuff... )
Everythig is working fine, components and services registered, controller created properly,
service
readonly ICRUDService<T> service;
in controller is of type
Castle.Proxies.IResourceService
But when i try to use service in controller i have error
Method Get is not supported on this proxy, this can happen if the method is
not marked with OperationContractAttribute or if the interface type is not
marked with ServiceContractAttribute.
When in controller i hardcode cast
((IResourceService)service).Get(id);
all is running properly, so i believe this problem is solvable.
I've also tried to use Forward (with same result) :
Component
.For<IActionTypeService>
.Forward<ICRUDService<DTOResource>>().AsWcfClient(...
How to make it work?
In the end i had to use 'Channel Factory' on client side.
I was able to use Windsor WCF Facility on server side to register generic contract :
[ServiceContract]
public interface ICRUDService<I>
{
[OperationContract]
I Get(int id);
}
with generic implementation
public class CRUDService<I, IEntity> : ServiceBase, ICRUDService<I>
{
public I Get(int id)
{
...
}
in standard way (for multiple types)
private void InstallExample<I, IEntity>(IWindsorContainer container)
{
container.Register(
Component
.For<ICRUDService<I>>()
.ImplementedBy(CRUDService<I, IEntity>)
.Named("somename")
.AsWcfService(
new DefaultServiceModel()
.Hosted()
.PublishMetadata(x => x.EnableHttpGet())
.AddEndpoints(WcfEndpoint
.BoundTo(new BasicHttpBinding())
.At("someAddress")
)
)
.LifeStyle.PerWcfOperation();
}
with fileless activation in web.config
<add factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" service="ClientService" relativeAddress="./ClientService.svc" />
On server side it works perfectly. Sadly on client side i didn't found working solution for WCFFacility and i had to use ChannelFactory (which is working perfectly)
ChannelFactory<ICRUDService<I>> factory = new ChannelFactory<ICRUDService<I>>(someBinding, someEndpoint);
For the rest (standard non generic services i'm using WCF Facility without any problems.
I think you need to put the ServiceContract attribute on ICrudService<>, add the OperationContract to the method there and remove the duplicate declaration of Get() from IResourceService.