Injecting SMTPclient into a behavior, how to test? - c#

I'm setting up an application and I'm injecting a bunch of behaviors into a service using Unity. There is a constructor, something like:
public class WhateverService(IBehavior[] behaviors) : IService {}
All of this is set up like while setting up the container, something like:
container.RegisterType<IBehavior, LogBehavior>("LogBehavior");
container.RegisterType<IBehavior, SomeOtherBehavior>("SomeOtherBehavior");
container.RegisterType<IService, WhateverService>();
Injection is done in the WCF service project, obviously.
Now I want to add a MailNotificationBehavior. So there's a bunch of SMTP settings that need to save somewhere. Since this SMTP config is a deployment thing, I want to use deafault web.config SMTP settings configurations.
The web.config is in the same project where the container configuration is being done, so the MailNotificationBehavior needs to be either injected with all of these settings, OR, just an instance of SmtpClient.
Something like:
container.RegisterType<IBehavior, MailNotificationBehavior>("MailNotificationBehavior", new new InjectionConstructor(new SmtpClient()));
Problem with this is - how will I be able to test this later on?
Should I write an interface ISmtpClient with an adapter for the actual SMTPClient, so I can fake it, or is this bad design to begin with?

Why are you relying on injection in your automated tests? You could/should write a unit test which instantiates the service and setups the service with mock "behaviours".
Reasoning: Your unit test should isolate the lines you want to test. Using injection makes your unit test also about testing if the injection works and if the right behaviour is available in the context of your service. You don't want either if you write a test for the service.
About the design; altough design by interface is nice, it's overdesign if you never plan on switching concrete smtp libraries. Another thing that kinda smells is creating "Behaviour". Your service does something (has effect on it's surroundings etc), that's it's behaviour. The behaviour of your service is calling a method on the implementations of IBehaviour and thereby changing the application state.
What you actually want to do is use AOP to add logging / email behaviour to your application by implementing them as aspects.

Related

How we can perform integration test on service fabric (stateless service)?

I'ld like to perform integration on stateless service in service fabric.Please help me on this. I have created the stateless service like c# web api.
In order to perform integration tests on your Reliable Service there is a number of dependencies you need to mock and take care of. You will not be able to test all situations or behavior of your service this way, the way the FabricRuntime hosts and runs services is difficult to replicate (without writing your own FabricRuntime equivalency). It is also worth noting that there is no way to run FabricRuntime without a cluster (including local development cluster).
You also need to consider how advanced your integration tests should be. For instance, does your service call out to other service (including actors) within the same cluster using fabric transport (the default communication model) that you want to include in your integration test? Do you need to ensure that state is persisted across multiple activations of the same service partition?
First you need to get rid of all hard dependencies to FabricRuntime (to things with dependencies to it) and also static support classes in your code:
Service/Actor proxy
Don't use the static ServiceProxy.Create<..)(..)> when calling other services, instead make sure your Service accepts an instance of IServiceProxyFactory in the constructor and use that instance to create proxies to services your service calls. Same goes for ActorProxy.Create<..>(..), replace this with an instance of IActorProxyFactory. In your program.cs where the service is constructed, give the service new ServiceProxyFactory() and new ActorProxyFactory(). That's the easy part, now you need to mock those so that your integration tests can actually create some form of proxy for downstream services. You will also need to create some form of container (like a mock FabricRuntime) that holds instances of called services and actors. It also gets tricky if you wan't to test that the RunAsync method of your service performs some function. Beware of creating this static though if you want to run it in a test runner,
you don't want different tests to get mixed up in the same container.
Service context
You need to mock your StatefulServiceContext well and how your Service is created. Your Service constructors need to accept an instance of StatefulServiceContext to pass along to the base class, so you are free to supply your own mocked instances of context there when you create the service.
public StatefulService(StatefulServiceContext serviceContext)
: base(serviceContext) {}
Service settings and activation context
You also need to see if your service implementation tries to read ICodePackageActivationContext or any of the settings from the Service manifest (like shown in this SO answer Where do you set and access run-time configuration parameters per environment for service fabric?). In that case you need to replace it with your own mockable version and you need to inject that in the constructor as well. What you find in most samples is a call to the service context, like this:
this.Context.CodePackageActivationContext.GetConfigurationPackageObject("Config");
If you do it this way in your service then you need make sure you have a mock of StatefulServiceContext as well and how your Service is created. When you register your service with the runtime in Program.Main() then you get and instance of StatefulServiceContext in the register call:
ServiceRuntime.RegisterServiceAsync("ServiceType",
context => new Service(context)).GetAwaiter().GetResult();
State
In order to mock state and get it to behave similar to what it will when running in a real cluster you need to mock the underlying handler for reliable state: IReliableStateManagerReplica and you need to add an overloaded constructor to your services that accepts an instance of that and sends it to the base:
public StatefulService(StatefulServiceContext serviceContext, IReliableStateManagerReplica reliableStateManagerReplica)
: base(serviceContext, reliableStateManagerReplica) {}
For actors its IActorStateProvider you need to mock if you want to handle state in your integration tests.
Summary
Depending on how advanced you want your integration tests to be and how close to the real execution model you want it to be, you may end up having to mock and replace a large number of classes/interfaces. The Web reference application sample
https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app has some implementation of Mocks for required classes, also https://github.com/loekd/ServiceFabric.Mocks contains Mocks for testing, although you might need to alter the code if you really want to run integration tests and not just unit tests.
There is no difference on your integration tests on stateless web api with a regular api.

Reuse WCF contract interface, but retain use of declarative configuration

We've used the solution in this old topic ("WCF Service Reference generates its own contract interface, won't reuse mine"), but that only solves the problem of reusing interfaces. What we would like to do, if possible, is to also retain the use of config files to setup and configure various options on WCF client side using all the bells and whistles of <system.serviceModel> node.
The approach that was given forces us to do all that in code, and that already proved to be a problem at one point (we had to change a binding configuration parameter which forced us to go through an entire corporate change request approval process to alter two lines in the code base, which is a huge hassle compared to a request to change config file).
Is there a solution that combines these two worlds?
Lets say you have IService as your service contract and it is shared between the client and the server.
Then in client code you would have something like this:
ChannelFactory<IService> factory = new ChannelFactory<IService>("ServiceClient");
var channel = factory.CreateChannel();
var result = channel.GetData(1);
In Client app.cofnig you would have a section that looks like this:
<system.serviceModel>
<client>
<endpoint name="ServiceClient" address="http://localhost:51377/service.svc" binding="basicHttpBinding"
contract="Common.IService"/>
</client>
</system.serviceModel>
Briefly explained ChannelFactory creates Channel to access IService service using ServiceClient endpoint configuration in app.config.
You can expand serviceModel configuration as you wish. Just add additional code to properly close channel once operation is complete.
What exactly is it that you're trying to achieve? Seems like you're trying to reuse contracts, but have SVCUTIL/VS generate the ClientBase<T>-derived class and modify the .config file?
If so, I don't think that's a supported scenario, really. Honestly, if you need to reuse your service contract interfaces, you might as well implement the ClientBase<T>-based proxy class by hand. It's only a little bit of additional work, and will make your life easier in the long run.
There isn't a supported option in SVCUTIL/VS to only import the binding configuration rather than the entire thing, though, so you'd likely need to write your config file by hand as well (or copy it from a manual run of SVCUTIL).

How to set WCF base addresses in code when using the Configure method

For pure code-based WCF configuration, in .NET 4.0 one could configure a base address for a service when creating an instance of a ServiceHost (assuming a self-hosted scenario, which is suitable for my needs). While one could still do this with .NET 4.5, MSDN implies that using the new Configure() method is a better practice because it makes such code-based configuration a bit easier for self-hosted and a lot easier for web hosted scenarios (see Configuring WCF Services in Code).
The problem, however, is that though the object you have to work with inside the Configure method (a System.ServiceModel.ServiceConfiguration) has a BaseAddresses property it is read-only. Surely there must be a way to set the base addresses in code? My web searches have turned up not only nothing about this specific question, but no articles or posts about this Configure method at all, except for the single MSDN page I have referenced!
Looking in reflector what BaseAddresses property does:
// System.ServiceModel.ServiceConfiguration
public ReadOnlyCollection<Uri> BaseAddresses
{
get
{
return this.host.BaseAddresses;
}
}
I was unable to find any other method in ServiceConfiguration working with ServiceHost.BaseAddresses
Instance of ServiceConfiguration is created using ServiceHost instance:
// System.ServiceModel.ServiceConfiguration
internal ServiceConfiguration(ServiceHost host)
{
ServiceConfiguration.CheckArgument<ServiceHost>(host, "host");
this.host = host;
}
This means that ServiceConfiguration is just an extension to standard way of configuring ServiceHost. So I would suggest any old way of setting BaseAddress is still considered as the best practice (programmatic or using configuration).

How can I host multiple IoC-driven WCF services in MVC?

I have around 6 WCF services that I want to host in an MVC application, routing requests to /services/foo to WcfFooService and /services/bar to WcfBarService
I can accomplish IoC with StructureMap within the services and inject my constructor dependencies by using the example that Jimmy Bogard blogged about here:
Jimmy's article is great, but I'm trying to extend it to work with multiple services hosted within the same MVC application. Essentially, the part at the bottom is the part that is causing me a few headaches:
public class StructureMapServiceHostFactory : ServiceHostFactory
{
public StructureMapServiceHostFactory()
{
ObjectFactory.Initialize(x => x.AddRegistry<FooRegistry>());
//var iTriedThisToo = ObjectFactory.Container;
//container.Configure(x => x.[etc]);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new StructureMapServiceHost(serviceType, baseAddresses);
}
}
With a single WCF service - routing MVC requests to a specific url via the StructureMapServiceHostFactory shown above works brilliantly - but - If (for example) I create a StructureMapServiceHostFactory2 for the /services/bar call, to allow for a different Registry to be used, when the MVC app spins up, it appears to call each factory in turn as it runs through RouteConfig.cs and adds the routes, so ultimately I don't get configured instances that the first ServiceHostFactory should provide.
It doesn't make a difference if I call Initialize(); or attempt to grab the Container property and call Configure on it, either.
Am I on a hiding to nothing with this? The major reason for requiring registry isolation is due to different NHibernate configuration, but I could configure Named instances of SessionFactory and Session for NHibernate purposes and then use a single registry to get around this. In my mind I wanted the WCF service and MVC-hosting to be capable of using their own IoC containers in isolation, which is why I went down this route.
Is there any way that I can accomplish this?
Ok, so it would appear the only person capable of answering this was me, by virtue of a re-think and 're-architecting' the solution so that the problem doesn't exist in the first place.
I now have a capable way of hosting these services and maintaining IoC with StructureMap neatly per service, without any conflicting concerns.
If you find yourself in a similar position with SOA taking over (SOATO?) - taking a step back is a good start ;)

Init properties in my base wcf service

I have set up some WCF services that I use to call from javascript to enable ajax calls such as retrieving data in JSON format.
All my services are configured in a web.config etc and I code in c#.
All my services inherit from a BaseService object which has some common properties that are share between all services, for example a logger object, configuration object etc.
My question is, how/where I can set up/assign values to these properties? ie. set up the base service logger property with an instant of a custom logger I created. Apologies if my question is vague but any help would be great.
Properties for Service implementation object cannot be set from client (any kind) because only contract is visible to client. Further, properties such as config and logger are anyway not meant to be part of contract but rather service implementation - so they must get set at server side automatically(i.e. by application infrastructure) for each service object. You have a couple of choices:
Use constructor (either that of BaseService or actual service class) to initialize these properties.
Use IoC/DependencyInjection container (for example, Unity, StructureMap)

Categories

Resources