Can anyone help, I am having problems using the auto-mocking that is available between Ninject and NSubstitute, actually the package is a ninject packaged called Ninject.MockingKernel.NSubstitute which should allow me to use Ninject to create mocks and return instances with mocks injected.
There seems to be a few examples for Moq and Rhinomocks but I don't see any for NSubstitute.
What I have so far is
this.kernel = new NSubstituteMockingKernel();
var summaryService = this.kernel.GetMock<IMyService>(); // GetMock not available
Anybody using it?
Here are a couple of examples adapted from the source code:
[TestFixture]
public class Tests
{
/// <summary>
/// Mocks are singletons.
/// </summary>
[Test]
public void MocksAreSingletons()
{
using (var kernel = new NSubstituteMockingKernel())
{
var firstReference = kernel.Get<IDummyService>();
var secondReference = kernel.Get<IDummyService>();
firstReference.Should().BeSameAs(secondReference);
}
}
/// <summary>
/// Real objects are created for auto bindable types.
/// </summary>
[Test]
public void RealObjectsAreCreatedForAutoBindableTypes()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance = kernel.Get<DummyClass>();
instance.Should().NotBeNull();
}
}
/// <summary>
/// Reals objects are singletons.
/// </summary>
[Test]
public void RealObjectsAreSingletons()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance1 = kernel.Get<DummyClass>();
var instance2 = kernel.Get<DummyClass>();
instance1.Should().BeSameAs(instance2);
}
}
/// <summary>
/// The injected dependencies are actually mocks.
/// </summary>
[Test]
public void TheInjectedDependenciesAreMocks()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance = kernel.Get<DummyClass>();
instance.DummyService.Do();
instance.DummyService.Received().Do();
}
}
public interface IDummyService
{
void Do();
}
public class DummyClass
{
public DummyClass(IDummyService dummyService)
{
this.DummyService = dummyService;
}
public IDummyService DummyService { get; set; }
}
}
Related
I have mocked RewriteContext:
Mock<RewriteContext> rewriteContextMock = new Mock<RewriteContext>();
Then I try to override its HttpContext with a mock:
rewriteContextMock.Setup(x => x.HttpContext.Request).Returns(requestMock.Object);
unfortunately that causes
Unsupported expression: x => x.HttpContext
Non-overridable members (here: RewriteContext.get_HttpContext) may not be used in setup / verification expressions.'
So what I did was
Mock<HttpContext> httpContextMock = new Mock<HttpContext>();
rewriteContextMock.Object.HttpContext = httpContextMock.Object;
But the the question raises: Is there any point in using Setup(), Return() chain when setting up the properites? Have I solved the problem correctly or I should use different approach?
RewriteContext is a simple POCO with no behavior,
/// <summary>
/// A context object for <see cref="RewriteMiddleware"/>
/// </summary>
public class RewriteContext
{
/// <summary>
/// Gets and sets the <see cref="HttpContext"/>
/// </summary>
public HttpContext HttpContext { get; set; }
/// <summary>
/// Gets and sets the File Provider for file and directory checks.
/// </summary>
public IFileProvider StaticFileProvider { get; set; }
/// <summary>
/// Gets and sets the logger
/// </summary>
public ILogger Logger { get; set; } = NullLogger.Instance;
/// <summary>
/// A shared result that is set appropriately by each rule for the next action that
/// should be taken. See <see cref="RuleResult"/>
/// </summary>
public RuleResult Result { get; set; }
internal StringBuilder Builder { get; set; } = new StringBuilder(64);
}
so there is no need to mock it.
All its members can be easily provided as needed to an actual instance of the object.
//...
RewriteContext rewriteContext = new RewriteContext();
var httpContext = new DefaultHttpContext();
httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("localhost");
//...set other members
rewriteContext.HttpContext = httpContext;
//...
My silverlight project has references to the RIA Services Silverlight Client and my .web application has access to RIAServices.Server.
I can't seem to find a good tutorial to learn how to connect these. Once I understand how to get the data from my NumberGenerator method. I can pick it up from there. I have three questions that I need some help with.
First, am I setting up this project correctly? I never done a project with RIA before.
Secondly what reference do I need to use ServiceContract(), FaultContract, and OperationContract? Most examples show that they are in the System.ServiceModel library. In this case with using the external library RIA Services Silverlight Client that is not the case. It throws a error saying I am missing a reference. What other libraries would have those three in it?
My last question is what URI do you use in the SystemDomainContext? Where I found the code at used this MyFirstRIAApplication-Web-EmployeeDomainService.svc but in my case I don't have anything that has a .svc extension. Would I use the .xap or .aspx?
Here is my Silverlight code
Here is my NumberGenerator Silverlight UserControl Page Code
public partial class NumberGenerator : UserControl
{
public NumberGenerator()
{
InitializeComponent();
GenerateNumber();
}
private void GenerateButton_Click(object sender, RoutedEventArgs e)
{
GenerateNumber();
}
private void GenerateNumber()
{
int result = 0
SystemClientServices systemclientservices = SystemClientServices.Instance;
result = systemclientservices.GenerateNumber();
NumberLabel.Content = result;
}
}
Here is my System Client Services class
private readonly static SystemClientServices _instance = new SystemClientServices();
private SystemDomainContext _domainContext = new SystemDomainContext();
private SystemClientServices() { }
public static SystemClientServices Instance
{
get
{
return _instance;
}
}
public int GenerateNumber()
{
//Code goes here to get the information from the Domainservices
LoadOperation load = this._domainContext.Load(this._domainContext.GetNumberGeneratorQuery(), LoadBehavior.KeepCurrent, false);
return Convert.ToInt32(load.Entities);
}
Here is my NumberGenerator class on the silverlight local project
public sealed partial class NumberGenerator : Entity
{
private static readonly NumberGenerator _instance = new NumberGenerator();
public int NumberGenerated { get; set; }
public NumberGenerator()
{
NumberGenerated = 0;
}
public static NumberGenerator Instance
{
get
{
return _instance;
}
}
}
Here is System Domain Conext class on the silverlight local project
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel.DomainServices;
using System.ServiceModel.DomainServices.Client;
using System.ServiceModel.DomainServices.Client.ApplicationServices;
using System.ServiceModel.Web;
using System.ServiceModel;
public sealed partial class SystemDomainConext : DomainContext
{
#region Extensibility Method Definitions
/// <summary>
/// This method is invoked from the constructor once initialization is complete and
/// can be used for further object setup.
/// </summary>
partial void OnCreated();
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeDomainContext"/> class.
/// </summary>
public SystemDomainConext() : this(new WebDomainClient<ISystemDomainServiceContract>(new Uri("MyFirstRIAApplication-Web-EmployeeDomainService.svc", UriKind.Relative)))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeDomainContext"/> class with the specified service URI.
/// </summary>
/// <param name="serviceUri">The EmployeeDomainService service URI.</param>
public SystemDomainConext(Uri serviceUri) : this(new WebDomainClient<ISystemDomainServiceContract>(serviceUri))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeDomainContext"/> class with the specified <paramref name="domainClient"/>.
/// </summary>
/// <param name="domainClient">The DomainClient instance to use for this DomainContext.</param>
public SystemDomainConext(DomainClient domainClient) : base(domainClient)
{
this.OnCreated();
}
/// <summary>
/// Gets the set of <see cref="Employee"/> entity instances that have been loaded into this <see cref="EmployeeDomainContext"/> instance.
/// </summary>
public EntitySet<NumberGenerator> GeneratedNumber
{
get
{
return base.EntityContainer.GetEntitySet<NumberGenerator>();
}
}
/// <summary>
/// Gets an EntityQuery instance that can be used to load <see cref="Employee"/> entity instances using the 'GetEmployee' query.
/// </summary>
/// <returns>An EntityQuery that can be loaded to retrieve <see cref="Employee"/> entity instances.</returns>
public EntityQuery<NumberGenerator> GetNumberGeneratorQuery()
{
this.ValidateMethod("GetGeneratedNumber", null);
return base.CreateQuery<NumberGenerator>("GetNumberGenerator", null, false, true);
}
/// <summary>
/// Creates a new EntityContainer for this DomainContext's EntitySets.
/// </summary>
/// <returns>A new container instance.</returns>
protected override EntityContainer CreateEntityContainer()
{
return new NumberGeneratorDomainContextEntityContainer();
}
/// <summary>
/// Service contract for the 'EmployeeDomainService' DomainService.
/// </summary>
[ServiceContract()]
public interface ISystemDomainServiceContract
{
/// <summary>
/// Asynchronously invokes the 'GetEmployee' operation.
/// </summary>
/// <param name="callback">Callback to invoke on completion.</param>
/// <param name="asyncState">Optional state object.</param>
/// <returns>An IAsyncResult that can be used to monitor the request.</returns>
[FaultContract(typeof(DomainServiceFault), Action="http://tempuri.org/EmployeeDomainService/GetEmployeeDomainServiceFault", Name="DomainServiceFault", Namespace="DomainServices")]
[OperationContract(AsyncPattern=true, Action="http://tempuri.org/EmployeeDomainService/GetEmployee", ReplyAction="http://tempuri.org/EmployeeDomainService/GetEmployeeResponse")]
[WebGet()]
IAsyncResult GetGeneratedNumber(AsyncCallback callback, object asyncState);
/// <summary>
/// Completes the asynchronous operation begun by 'BeginGetEmployee'.
/// </summary>
/// <param name="result">The IAsyncResult returned from 'BeginGetEmployee'.</param>
/// <returns>The 'QueryResult' returned from the 'GetEmployee' operation.</returns>
QueryResult<NumberGenerator> EndGetGeneratedNumber(IAsyncResult result);
/// <summary>
/// Asynchronously invokes the 'SubmitChanges' operation.
/// </summary>
/// <param name="changeSet">The change-set to submit.</param>
/// <param name="callback">Callback to invoke on completion.</param>
/// <param name="asyncState">Optional state object.</param>
/// <returns>An IAsyncResult that can be used to monitor the request.</returns>
[FaultContract(typeof(DomainServiceFault), Action="http://tempuri.org/EmployeeDomainService/SubmitChangesDomainServiceFault", Name="DomainServiceFault", Namespace="DomainServices")]
[OperationContract(AsyncPattern=true, Action="http://tempuri.org/EmployeeDomainService/SubmitChanges", ReplyAction="http://tempuri.org/EmployeeDomainService/SubmitChangesResponse")]
IAsyncResult BeginSubmitChanges(IEnumerable<ChangeSetEntry> changeSet, AsyncCallback callback, object asyncState);
/// <summary>
/// Completes the asynchronous operation begun by 'BeginSubmitChanges'.
/// </summary>
/// <param name="result">The IAsyncResult returned from 'BeginSubmitChanges'.</param>
/// <returns>The collection of change-set entry elements returned from 'SubmitChanges'.</returns>
IEnumerable<ChangeSetEntry> EndSubmitChanges(IAsyncResult result);
}
internal sealed class NumberGeneratorDomainContextEntityContainer : EntityContainer
{
public NumberGeneratorDomainContextEntityContainer()
{
this.CreateEntitySet<NumberGenerator>(EntitySetOperations.Edit);
}
}
}
Here is my System Domain Services class that is on the Silverlight.web
[EnableClientAccess()]
public class SystemDomainServices : DomainService
{
private NumberGenerator numberGenerator = NumberGenerator.Instance;
public int NumberGenerate()
{
return numberGenerator.NumberGenerated;
}
}
Here is the NumberGenerator class on the silverlight.web
private static readonly NumberGenerator _instance = new NumberGenerator();
[Key]
public int NumberGenerated { get; set; }
public NumberGenerator()
{
NumberGenerated = GenerateNumber();
}
public static NumberGenerator Instance
{
get
{
return _instance;
}
}
public int GenerateNumber()
{
string db_date = "";
int db_num = 0;
string todaysdate = "";
int temp_num = db_num;
int result = 0;
using (SqlConnection connection = new SqlConnection(DBConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand("SELECT * FROM table", connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
db_date = reader.GetString(0);
db_num = (int)(reader.GetSqlInt32(1));
todaysdate = DateTime.Now.ToString("yMMdd");
temp_num = db_num;
}
reader.Close();
}
if (todaysdate != db_date)
{
using (SqlCommand dateUpate = new SqlCommand("UPDATE table SET tsDate='" + todaysdate + "' WHERE tsDate='" + db_date + "'", connection))
{
dateUpate.ExecuteNonQuery();
}
db_num = 0;
db_date = todaysdate;
}
db_num++;
using (SqlCommand numUpate = new SqlCommand("UPDATE table SET tsNum='" + db_num + "' WHERE tsNum='" + temp_num + "'", connection))
{
numUpate.ExecuteNonQuery();
}
result = Convert.ToInt32(db_date + db_num.ToString().PadLeft(3, '0'));
connection.Close();
connection.Dispose();
}
return result;
}
}
The answer to question two you might be have to go to Tools at the top, NuGet Package Manager, Package Management Console, and then type the following command to install the package for those three functions.
PM> Install-Package RIAServices.Silverlight.DomainDataSource
Is there any way to inject dependencies in to the Azure Service Fabric Actor's constructor?
Updated
Its all on github and myget now: https://github.com/s-innovations/S-Innovations.ServiceFabric.Unity
and integrates with aspnet core dependency injection without to much hassle, check the examples of the readme.md
I am a long time user of Unity and decided to make the core extension methods needed to have a nice dependency injection experience when working with actors.
My program.cs now looks like this:
internal static class Program
{
/// <summary>
/// This is the entry point of the service host process.
/// </summary>
private static void Main()
{
try
{
using (var container = new UnityContainer())
{
container.RegisterType<IMessageProcessorClientFactory, DummyFactory>(new HierarchicalLifetimeManager());
container.RegisterType<IMessageClusterConfigurationStore, test>(new HierarchicalLifetimeManager());
container.WithFabricContainer();
container.WithActor<MessageClusterActor>();
container.WithActor<QueueListenerActor>();
container.WithStatelessFactory<ManagementApiServiceFactory>("ManagementApiServiceType");
container.WithActor<VmssManagerActor>();
ServiceFabricEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(ManagementApiService).Name);
Thread.Sleep(Timeout.Infinite); // Prevents this host process from terminating to keep the service host process running.
}
}
catch (Exception e)
{
ServiceFabricEventSource.Current.ActorHostInitializationFailed(e.ToString());
throw;
}
}
}
where I in actors and services can just put in my dependencies in the constructors.
public class VmssManagerActor : StatefulActor<VmssManagerActor.ActorState>, IVmssManagerActor, IRemindable
{
public const string CheckProvision = "CheckProvision";
/// <summary>
/// Cluster Configuration Store
/// </summary>
protected IMessageClusterConfigurationStore ClusterConfigStore { get; private set; }
public VmssManagerActor(IMessageClusterConfigurationStore clusterProvider)
{
ClusterConfigStore = clusterProvider;
}
If you feel this is useful and would like me to put it into a nuget package, upvote this answer.
One note about the implementation, each actor will get its own scope. This means that all dependencies registered with 'HierarchicalLifetimeManager' that implements IDisposable will automaticly get disposed in the actor OnDeactivationAsync. This was done by dynamicly proxying the actor class with a dynamic type that intercepts the call to OnDeactivationAsync. For this to work the Actor must be public defined.
IActorDeactivationInterception.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Abstraction
{
/// <summary>
/// The <see cref="IActorDeactivationInterception"/> interface for defining an OnDeactivateInterception
/// </summary>
public interface IActorDeactivationInterception
{
void Intercept();
}
}
ActorProxyTypeFactory.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class ActorProxyTypeFactory
{
/// <summary>
/// Creates a new instance of the <see cref="ActorProxyTypeFactory"/> class.
/// </summary>
/// <param name="target"></param>
public ActorProxyTypeFactory(Type target)
{
this.target = target;
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public static T Create<T>(IActorDeactivationInterception deactivation, params object[] args)
{
return (T)new ActorProxyTypeFactory(typeof(T)).Create(new object[] { deactivation }.Concat(args).ToArray());
}
public static Type CreateType<T>()
{
return new ActorProxyTypeFactory(typeof(T)).CreateType();
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public object Create(object[] args)
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return Activator.CreateInstance(proxy, args);
}
public Type CreateType()
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return proxy;
// return Activator.CreateInstance(proxy, args);
}
/// <summary>
/// Builds a dynamic assembly with <see cref="AssemblyBuilderAccess.RunAndSave"/> mode.
/// </summary>
/// <returns></returns>
public void BuidAssembly()
{
AssemblyName assemblyName = new AssemblyName("BasicProxy");
AssemblyBuilder createdAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
// define module
this.moduleBuilder = createdAssembly.DefineDynamicModule(assemblyName.Name);
}
public void BuildType()
{
if (!target.IsPublic)
{
throw new ArgumentException("Actors have to be public defined to proxy them");
}
this.typeBuilder =
this.moduleBuilder.DefineType(target.FullName + "Proxy", TypeAttributes.Class | TypeAttributes.Public, target);
this.fldInterceptor = this.typeBuilder.DefineField("interceptor", typeof(IActorDeactivationInterception), FieldAttributes.Private);
foreach (var constructor in target.GetConstructors())
{
// Type[] parameters = new Type[1];
ParameterInfo[] parameterInfos = constructor.GetParameters();
Type[] parameters = new Type[parameterInfos.Length + 1];
parameters[0] = typeof(IActorDeactivationInterception);
for (int index = 1; index <= parameterInfos.Length; index++)
{
parameters[index] = parameterInfos[index - 1].ParameterType;
}
ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameters);
for (int argumentIndex = 0; argumentIndex < parameters.Length; argumentIndex++)
constructorBuilder.DefineParameter(
argumentIndex + 1,
ParameterAttributes.None,
$"arg{argumentIndex}");
ILGenerator generator = constructorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
for (int index = 1; index < parameters.Length; index++)
{
generator.Emit(OpCodes.Ldarg, index + 1);
}
generator.Emit(OpCodes.Call, constructor);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, fldInterceptor);
generator.Emit(OpCodes.Ret);
}
}
/// <summary>
/// Builds a type in the dynamic assembly, if already the type is not created.
/// </summary>
/// <returns></returns>
public void InterceptAllMethods()
{
const MethodAttributes targetMethodAttributes =
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
var methodInfo = target.GetMethod("OnDeactivateAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
{
if (methodInfo.IsVirtual)
{
Type[] paramTypes = GetParameterTypes(methodInfo.GetParameters());
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(methodInfo.Name, targetMethodAttributes, methodInfo.ReturnType, paramTypes);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fldInterceptor);
ilGenerator.Emit(OpCodes.Call, typeof(IActorDeactivationInterception).GetMethod("Intercept"));
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, methodInfo);
ilGenerator.Emit(OpCodes.Ret);
return;
}
}
}
private Type[] GetParameterTypes(ParameterInfo[] parameterInfos)
{
Type[] parameters = new Type[parameterInfos.Length];
int index = 0;
foreach (var parameterInfo in parameterInfos)
{
parameters[index++] = parameterInfo.ParameterType;
}
return parameters;
}
private TypeBuilder typeBuilder;
private ModuleBuilder moduleBuilder;
private readonly Type target;
private FieldInfo fldInterceptor;
}
}
OnActorDeactivateInterceptor.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using Microsoft.Practices.Unity;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class OnActorDeactivateInterceptor : IActorDeactivationInterception
{
private readonly IUnityContainer container;
public OnActorDeactivateInterceptor(IUnityContainer container)
{
this.container = container;
}
public void Intercept()
{
this.container.Dispose();
}
}
}
UnityFabricExtensions.cs
namespace SInnovations.Azure.ServiceFabric.Unity
{
using System;
using System.Fabric;
using Microsoft.Practices.Unity;
using Microsoft.ServiceFabric.Actors;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
using SInnovations.Azure.ServiceFabric.Unity.Actors;
public static class UnityFabricExtensions
{
public static IUnityContainer WithFabricContainer(this IUnityContainer container)
{
return container.WithFabricContainer(c => FabricRuntime.Create());
}
public static IUnityContainer WithFabricContainer(this IUnityContainer container, Func<IUnityContainer,FabricRuntime> factory)
{
container.RegisterType<FabricRuntime>(new ContainerControlledLifetimeManager(), new InjectionFactory(factory));
return container;
}
public static IUnityContainer WithActor<TActor>(this IUnityContainer container) where TActor : ActorBase
{
if (!container.IsRegistered<IActorDeactivationInterception>())
{
container.RegisterType<IActorDeactivationInterception, OnActorDeactivateInterceptor>(new HierarchicalLifetimeManager());
}
container.RegisterType(typeof(TActor), ActorProxyTypeFactory.CreateType<TActor>(),new HierarchicalLifetimeManager());
container.Resolve<FabricRuntime>().RegisterActorFactory(() => {
try {
var actor = container.CreateChildContainer().Resolve<TActor>();
return actor;
}
catch (Exception ex)
{
throw;
}
});
return container;
}
public static IUnityContainer WithStatelessFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatelessServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatelessServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithStatefulFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatefulServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatefulServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithService<TService>(this IUnityContainer container, string serviceTypeName)
{
container.Resolve<FabricRuntime>().RegisterServiceType(serviceTypeName, typeof(TService));
return container;
}
}
}
I know this is old but for documentations' sake DI is now supported in the Reliable Actor framework just like you would expect.
public class ActorOne : Actor<MyActorState>, IMyActor{
private readonly IDependency _dependency;
public ActorOne(IDependency dependency)
{
_dependency = dependency;
}}
And then you register the Actor with its dependency with the Service Fabric like this:
using (FabricRuntime fRuntime = FabricRuntime.Create()){
fRuntime.RegisterActor(() => new ActorOne(new MyDependency());
Thread.Sleep(Timeout.Infinite);}
Having had a bit of a dig-around in this area with dotPeek a while back (trying to resolve actors from an Autofac lifetime scope per-invocation), I think the trick is to create your own implementation of StatelessActorServiceFactory, and your own extension method to register the actor with it. Although the factory class is marked as internal, its interface (IStatelessServiceFactory) and the service type it creates (StatelessActorServiceInstance) are both public. Unfortunately, it doesn't look like StatelessActorServiceInstance was designed to be extensible (I'm hoping this is just an oversight).
Unfortunately, it looks like WcfActorCommunicationProvider is also marked as internal so you'll pretty much have to create your own pipeline from scratch:
Implement your own IStatelessServiceFactory
Implement your own IStatelessServiceInstance, IActorService
Implement your own IActorCommunicationProvider
Implement your own IActorHost
Doesn't really seem worth the effort anymore, does it? :-/
That's where I gave up for now. I don't think it's worth trying to roll-your-own for now given the relative immaturity of the public API, since if this sort of functionality will show up at all, they'll probably do so in a way that'll break anything your implement yourself.
Why not just use some root element field in actor, and resolve it from container with injected dependencies in Actor's constructor? If this is a bad decision, please explain why:
public class StatelessActor2 : Actor, IStatelessActor2
{
private ConfiguredContainer _container;
private IRootElement _rootElement;
public StatelessActor2()
{
_container = new ConfiguredContainer(); //... container is configured in it's constructor
_rootElement = _container.Resolve<IRootElement>();
}
public async Task<string> DoWorkAsync()
{
// Working with a RootElement with all dependencies are injected..
return await Task.FromResult(_rootElement.WorkingWithInjectedStuff());
}
}
If you're using Autofac, they have a specific integration package for that:
https://alexmg.com/introducing-the-autofac-integration-for-service-fabric/
https://www.nuget.org/packages/Autofac.ServiceFabric/
In short, registration is performed using ActorRuntime.RegisterActorAsync / ServiceRuntime.RegisterServiceAsync as you would expect. However the more problematic part, namely object release, is automatically handled in the OnDeactivateAsync / OnCloseAsync / OnAbort overrides using a dynamic proxy. Proper lifetime scoped is maintained as well.
At the time of writing it's still in Alpha though (just released last month).
#abatishchev I think you are referring to the Service-Locator antipattern. Both Dependency Injection and Service-Locator are variations of Inversion of Control.
https://www.martinfowler.com/articles/injection.html
I have the following setup: A console application, and a services project with a range of services.
I am trying to use Windsor Castle to install specific services in the application, depending on their namespace in the application.
I have got the following to work fine in my application:
Container.Install(Castle.Windsor.Installer.Configuration.FromXmlFile("components.config"));
However, I have trouble getting the "register all service with specific namespace to work".
In a web application I have made previously, I got the following code to work. However, it seems that when I use Container.Register in my console application, I cannot resolve the services later on.
Code I've previously used in a web application:
// All services in service DLL
var assembly = Assembly.LoadFrom(Server.MapPath("~/bin/LetterAmazer.Business.Services.dll"));
;
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.FulfillmentJobs")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.PaymentMethods.Implementations")
.WithServiceAllInterfaces());
// All factories in service DLL
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Factory")
.WithServiceAllInterfaces());
Container.Register(Component.For<LetterAmazerEntities>());
When I use the Container.Register code in my console application, I cannot do the following:
orderService = ServiceFactory.Get<IOrderService>();
fulfillmentService = ServiceFactory.Get<IFulfillmentService>();
As I get a "service could not be resolved".
The code is run in a BackgroundService class, with the following code:
public void Start()
{
logger.Info("Starting Background Service...");
Container.Install(Castle.Windsor.Installer.Configuration.FromXmlFile("components.config"));
ISchedulerFactory scheduleFactory = new StdSchedulerFactory();
scheduler = scheduleFactory.GetScheduler();
scheduler.Start();
ThreadStart threadStart = new System.Threading.ThreadStart(ScheduleJobs);
new Thread(threadStart).Start();
logger.Info("DONE!");
}
So to sum it all up: how do register all services / classes with a specific namespace, in an external DLL, in a console application?
EDIT:
ServiceFactory.cs:
public class ServiceFactory
{
private static ServiceFactory instance = new ServiceFactory();
private IWindsorContainer container = new WindsorContainer();
private ServiceFactory()
{
}
/// <summary>
/// Gets the container.
/// </summary>
/// <value>The container.</value>
public static IWindsorContainer Container
{
get { return instance.container; }
}
/// <summary>
/// Gets this instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Get<T>()
{
return instance.container.Resolve<T>();
}
/// <summary>
/// Gets all this instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IList<T> GetAll<T>()
{
return instance.container.ResolveAll<T>();
}
/// <summary>
/// Gets the specified name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name">The name.</param>
/// <returns></returns>
public static T Get<T>(string name)
{
return (T)instance.container.Resolve<T>(name);
}
/// <summary>
/// Gets all the specified name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name">The name.</param>
/// <returns></returns>
public static IList<T> GetAll<T>(string name)
{
return instance.container.ResolveAll<T>(name);
}
}
EDIT-2
If I try to make a resolve in the BackgroundService, after registering the services to my container, I get a:
An unhandled exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll
Additional information: No component for supporting the service LetterAmazer.Business.Services.Domain.Orders.IOrderService was found
However, I can see that in debug, the IOrderService exists in the "All services" in my container.
EDIT-3
public interface IOrderService
{
Order Create(Order order);
Order Update(Order order);
void UpdateByLetters(IEnumerable<Letter> letters);
List<Order> GetOrderBySpecification(OrderSpecification specification);
Order GetOrderById(int orderId);
Order GetOrderById(Guid orderId);
void Delete(Order order);
List<OrderLine> GetOrderLinesBySpecification(OrderLineSpecification specification);
void ReplenishOrderLines(Order order);
}
EDIT-4: Order service
Note: some of the implementation has been cut
public class OrderService : IOrderService
{
private IOrderFactory orderFactory;
private LetterAmazerEntities repository;
private ILetterService letterService;
private ICustomerService customerService;
public OrderService(LetterAmazerEntities repository,
ILetterService letterService,
IOrderFactory orderFactory, ICustomerService customerService)
{
this.repository = repository;
this.letterService = letterService;
this.orderFactory = orderFactory;
this.customerService = customerService;
}
public Order Create(Order order)
{
DbOrders dborder = new DbOrders();
foreach (var orderLine in order.OrderLines)
{
var dbOrderLine = setOrderline(orderLine);
dborder.DbOrderlines.Add(dbOrderLine);
}
dborder.Guid = Guid.NewGuid();
dborder.OrderCode = GenerateOrderCode();
dborder.OrderStatus = (int)OrderStatus.Created;
dborder.DateCreated = DateTime.Now;
dborder.DateUpdated = DateTime.Now;
dborder.PaymentMethod = "";
dborder.CustomerId = order.Customer != null ? order.Customer.Id : 0;
Price price = new Price();
price.PriceExVat = order.CostFromLines();
price.VatPercentage = order.Customer.VatPercentage();
order.Price = price;
dborder.Total = order.Price.Total;
dborder.VatPercentage = order.Price.VatPercentage;
dborder.PriceExVat = order.Price.PriceExVat;
repository.DbOrders.Add(dborder);
repository.SaveChanges();
return GetOrderById(dborder.Id);
}
public Order GetOrderById(Guid orderId)
{
DbOrders dborder = repository.DbOrders.FirstOrDefault(c => c.Guid == orderId);
if (dborder == null)
{
throw new ItemNotFoundException("Order");
}
var lines = repository.DbOrderlines.Where(c => c.OrderId == dborder.Id).ToList();
var order = orderFactory.Create(dborder, lines);
return order;
}
public Order GetOrderById(int orderId)
{
DbOrders dborder = repository.DbOrders.FirstOrDefault(c => c.Id == orderId);
if (dborder == null)
{
throw new ItemNotFoundException("Order");
}
var lines = repository.DbOrderlines.Where(c => c.OrderId == orderId).ToList();
var order = orderFactory.Create(dborder, lines);
return order;
}
public void Delete(Order order)
{
var dborder = repository.DbOrders.FirstOrDefault(c => c.Id == order.Id);
repository.DbOrders.Remove(dborder);
repository.SaveChanges();
}
public void DeleteOrder(Order order)
{
var dborder = repository.DbOrders.FirstOrDefault(c => c.Id == order.Id);
repository.DbOrders.Remove(dborder);
repository.SaveChanges();
}
#endregion
}
I think you can do the same thing in a console application too. You just have to create the assembly instance. Considering that the assembly is in the same folder, this should work:
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("MyNamespace")
.WithServiceAllInterfaces());
Consider the sample code below consisting of a Class Library design and an executable Program using the library.
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
m_StageApp = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
// Question: How to add actor to stage?
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
Question
Stage and Actor have circular dependency and seems bad to me.
For example, how should we add actors to stage?
If I let user to create new Actor() themselves,
then they must keep on supplying the Stage.
If I give Actor() an internal constructor and make Stage a factory,
then I lose some of the flexibility for users to do making inherited Actors.
If I make Stage a singleton, then I can only have one set of SharedSetting.
In case the user wants more than one Stage in his AppExe, then it cannot be done.
Is there anyway to redesign the architecture so as to avoid the problems above?
If your functionality is not limited by sharing the StageApp settings between actors, but also will be some other logic. For example when you need to know parent StageApp from Actor and vice versa. I preffer to implement it in this way:
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public int TotalActorsCount
{
get
{
return m_actors.Count;
}
}
public void AddActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (m_actors.Contains(actor))
return; // or throw an exception
m_actors.Add(actor);
if (actor.Stage != this)
{
actor.Stage = this;
}
}
// we are hiding this method, to avoid because we can change Stage only to another non null value
// so calling this method directly is not allowed
internal void RemoveActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (!m_actors.Contains(actor))
return; // or throuw exception
m_actors.Remove(actor);
}
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
public StageApp Stage
{
get
{
return m_StageApp;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (m_StageApp != value)
{
if (m_StageApp != null) // not a call from ctor
{
m_StageApp.RemoveActor(this);
}
m_StageApp = value;
m_StageApp.AddActor(this);
}
}
}
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
Stage = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
StageApp anotherApp = new StageApp();
anotherApp.SharedSetting = 6;
// actor is added to the stage automatically after instantiation
Actor a1 = new Actor(app);
Actor a2 = new Actor(app);
Actor a3 = new Actor(anotherApp);
Console.WriteLine("Actors in anotherApp before moving actor:");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by calling method from StageApp class
anotherApp.AddActor(a1);
Console.WriteLine("Actors in anotherApp after calling method (should be 2):");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by setting Stage through property
a2.Stage = anotherApp;
Console.WriteLine("Actors in anotherApp after setting property of Actor instance (should be 3):");
Console.WriteLine(anotherApp.TotalActorsCount);
Console.WriteLine("Actors count in app (should be empty):");
Console.WriteLine(app.TotalActorsCount);
}
}
}
It allows to you to manipulate with object relationships transparently, but requires a little bit mor code to implement.
How about adding a new class "ActorRole" that defines the behaviour of the actor in each Stage. It lets you decouple Actor and Stage from each other, so you can instantiate both independently (through a factory for example) and then combine them creating ActorRole objects that configure your stages. This combinations can be made using a Builder pattern if it is needed.
If you need to dynamically change your actor behaviour, you can use a Strategy pattern based on the ActorRole class, so depending on the Stage, you can assign to the actor different concrete implementations of its behaviour.
I would solve it by using Func instead of passing in the Stage to the Actor. Like this:
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.CreateActor();
app.SharedSetting = 5;
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
namespace AppLib
{
class StageApp
{
public int SharedSetting { get; set; }
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public void CreateActor()
{
m_actors.Add(new Actor(Executed));
}
private int Executed(int arg)
{
return SharedSetting * arg;
}
}
class Actor
{
private int m_Property;
private Func<int, int> m_executed;
public Actor(Func<int, int> executed)
{
m_executed = executed;
m_Property = new Random().Next();
}
public int Execute()
{
return m_executed(m_Property);
}
}
}
I totally agree with you that circular references is not fun :).
You could also solve this using events, but I like passing functions like callback.