I have a problem. I'm implementing a selfhost web api based on Owin and Castle. My interface looks like this:
public interface IFluentStoredProcedureRunner<T> where T : class
{
FluentStoredProcedureRunner<T> WithName(string storedProcedureName);
FluentStoredProcedureRunner<T> WithParameters(List<StoredProcedureParameterDefinition> parameterList = null);
StoredProcedureResult<T> Run();
}
and the implementation looks like this:
public class FluentStoredProcedureRunner<T> : IFluentStoredProcedureRunner<T> where T : class
{
private readonly IStoredProcedureRunner<T> storedProcedureRunner;
private string storedProcedureName = string.Empty;
private List<StoredProcedureParameterDefinition> parameterList = new List<StoredProcedureParameterDefinition>();
public FluentStoredProcedureRunner(IStoredProcedureRunner<T> storedProcedureRunner)
{
this.storedProcedureRunner = storedProcedureRunner;
}
public FluentStoredProcedureRunner<T> WithName(string storedProcedureName)
{
this.storedProcedureName = storedProcedureName;
return this;
}
public FluentStoredProcedureRunner<T> WithParameters(List<StoredProcedureParameterDefinition> parameterList = null)
{
this.parameterList = parameterList;
return this;
}
public StoredProcedureResult<T> Run()
{
return this.storedProcedureRunner.Run(this.storedProcedureName, this.parameterList);
}
}
and the registrations:
public class CoreLibInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For(typeof(IMapper<>))
.ImplementedBy(typeof(MapByFieldNameMapper<>))
.LifestyleTransient());
container.Register(
Component.For(typeof(IStoredProcedureRunner<>))
.ImplementedBy(typeof(StoredProcedureRunner<>))
.LifestyleTransient());
container.Register(
Component.For(typeof(IFluentStoredProcedureRunner<>))
.ImplementedBy(typeof(FluentStoredProcedureRunner<>))
.LifestyleTransient());
container.Register(
Component.For<IAuthenticationService>()
.ImplementedBy<ActiveDirectoryAuthenticationService>()
.LifestyleTransient());
container.Register(
Component.For<IStoredProcedureNameResolverService>()
.ImplementedBy<StoredProcedureNameResolverService>()
.LifestyleTransient());
}
}
Here is the stored procedure runner:
public class StoredProcedureRunner<T> : IStoredProcedureRunner<T> where T : class, new()
{
private const string ConnectionString = "someConnectionString"
private readonly IMapper<T> mapper;
private readonly StoredProcedureResult<T> storedProcedureResult = new StoredProcedureResult<T>();
public StoredProcedureRunner(IMapper<T> mapper)
{
this.mapper = mapper;
}
public StoredProcedureResult<T> Run(
string storedProcedureName,
List<StoredProcedureParameterDefinition> parametersList = null)
{
try
{
using (var conn = new IfxConnection(ConnectionString))
{
conn.Open();
using (var cmd = new IfxCommand())
{
cmd.Connection = conn;
cmd.CommandText = storedProcedureName;
cmd.CommandType = CommandType.StoredProcedure;
if (parametersList != null)
{
foreach (var parameter in parametersList)
{
var parameterToAdd = new IfxParameter
{
ParameterName = parameter.ParameterName,
IfxType = parameter.ParameterType,
Value = parameter.ParamerValue,
Direction = parameter.ParameterDirection
};
cmd.Parameters.Add(parameterToAdd);
}
}
var ifxdr = cmd.ExecuteReader();
this.storedProcedureResult.Rows = this.mapper.Map(ifxdr).ToList();
if (parametersList != null)
{
foreach (var outputParameter in parametersList.Where(pl => pl.ParameterDirection == ParameterDirection.Output))
{
this.storedProcedureResult.OutputParameters.Add(
outputParameter.ParameterName,
cmd.Parameters[outputParameter.ParameterName].Value);
}
}
return this.storedProcedureResult;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
}
This is the interface for it:
public interface IStoredProcedureRunner<T> where T : class
{
StoredProcedureResult<T> Run(
string storedProcedureName,
List<StoredProcedureParameterDefinition> parametersList = null);
}
The problem is that after all of that It is throwing the exception:
ComponentActivator: could not instantiate
StoreProcRunLib.DB.StoredProcedureRunner.FluentStoredProcedureRunner`1[[PromakGateway.WebApi.Models.InactiveAccountsTransferModel,
PromakGateway.WebApi, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]
I've seen here Castle Windsor - IoC registration for open generic interfaces? that there is an adapter of some kind but I don't know how it looks like. Thanks in advance.
Related
I have the following class and methods, that will be connecting to a DB, but for testing, I do not need the real connection and would need to fake it. We're using FakeItEasy for this.:
public abstract class HandlerBase
{
public string errorMessage;
private MyActionsDataModel Action
{
get
{
if (_action == null)
{
_action = new MyActionsDataModel();
using (var connection = new SqlConnection(Constants.Connections.MyDatabase))
{
connection.Open();
using (var transaction = connection.BeginTransaction(IsolationLevel.Serializable))
{
_action.Id = connection.QuerySingle<int>("UpdateAction", transaction: transaction, commandType: CommandType.StoredProcedure, param: Action);
transaction.Commit();
}
}
}
return _action;
}
}
private MyActionsDataModel _action;
public void RecordFailure(AggregateException ex)
{
Console.WriteLine("A failure happened:");
Console.WriteLine(JsonConvert.SerializeObject(ex));
errorMessage = "Inner Exception\r\n" + ex.Message;
Action.ErrorOccurredOnUtc = DateTimeOffset.UtcNow;
Action.ErrorType = ex.GetType().FullName;
Action.ErrorMessage = errorMessage;
SaveAction();
}
private void SaveAction()
{
using (var connection = new SqlConnection(Constants.Connections.MyDatabase))
{
connection.Open();
using (var transaction = connection.BeginTransaction(IsolationLevel.Serializable))
{
connection.Execute("UpdateAction", transaction: transaction,
commandType: CommandType.StoredProcedure, param: Action);
transaction.Commit();
}
}
}
}
another class that I'll be calling in my tests:
public class MyHandlerType : HandlerBase
{
private readonly MyTracker _myTracker;
public MyHandlerType(MyTracker myTracker) : base()
{
_myTracker = myTracker;
}
}
What I want is to Fake the Action parameter and also SaveAction method.
Here is the Test I have for it, but not sure how to make the Fake part.
public class HandlerTests
{
[TestCase]
public void Test_RecordFailure()
{
var innerMessage = "Throw AppException for UnitTest.";
var parentMessage = "Throw AggregationException for UnitTest.";
var testHandler = new MyHandlerType(null);
var innerException = new ApplicationException(innerMessage);
var parentException = new AggregateException(parentMessage, innerException);
testHandler.RecordFailure(parentException);
var includeInnerMessage = testHandler.errorMessage.Contains(innerMessage);
var includeParentMessage = testHandler.errorMessage.Contains(parentMessage);
Assert.IsTrue(includeInnerMessage);
Assert.IsTrue(includeParentMessage);
}
}
The current class is tightly coupled to implementation concerns that make testing it in isolation difficult.
Consider refactoring the class
public abstract class HandlerBase {
private readonly Lazy<MyActionsDataModel> model;
private readonly IDbConnectionFactory connectionFactory;
protected HandlerBase(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
model = new Lazy<MyActionsDataModel>(() => {
MyActionsDataModel action = new MyActionsDataModel();
using (DbConnection connection = this.connectionFactory.Create()) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
action.Id = connection.QuerySingle<int>("UpdateAction",
transaction: transaction,
commandType: CommandType.StoredProcedure,
param: action);
transaction.Commit();
}
}
return action;
});
}
public string ErrorMessage;
public void RecordFailure(AggregateException ex) {
Console.WriteLine("A failure happened:");
Console.WriteLine(JsonConvert.SerializeObject(ex));
ErrorMessage = "Inner Exception\r\n" + ex.Message;
MyActionsDataModel action = model.Value;
action.ErrorOccurredOnUtc = DateTimeOffset.UtcNow;
action.ErrorType = ex.GetType().FullName;
action.ErrorMessage = ErrorMessage;
saveAction(action);
}
private void saveAction(MyActionsDataModel action) {
using (DbConnection connection = connectionFactory.Create()) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
connection.Execute("UpdateAction", transaction: transaction,
commandType: CommandType.StoredProcedure, param: action);
transaction.Commit();
}
}
}
}
Note the introduction of an explicit dependency
public interface IDbConnectionFactory {
DbConnection Create();
}
which can have an implementation
// Connection Factory method
public DbConnection Create() {
DbConnection connection = new SqlConnection(Constants.Connections.MyDatabase);
return connection;
}
When testing the factory can be mocked to behave as desired when the subject under test is exercised.
Here is my new code (based on the suggestion from #Nkosi) and the test part:
CODE:
public abstract class HandlerBase {
private readonly Lazy<MyActionsDataModel> model;
private readonly IDbConnectionFactory connectionFactory;
protected HandlerBase(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
model = new Lazy<MyActionsDataModel>(() => {
MyActionsDataModel action = new MyActionsDataModel();
using (DbConnection connection = this.connectionFactory.Create()) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
action.Id = connection.QuerySingle<int>("UpdateAction",
transaction: transaction,
commandType: CommandType.StoredProcedure,
param: action);
transaction.Commit();
}
}
return action;
});
}
public string ErrorMessage;
public void RecordFailure(AggregateException ex) {
Console.WriteLine("A failure happened:");
Console.WriteLine(JsonConvert.SerializeObject(ex));
ErrorMessage = "Inner Exception\r\n" + ex.Message;
MyActionsDataModel action = model.Value;
action.ErrorOccurredOnUtc = DateTimeOffset.UtcNow;
action.ErrorType = ex.GetType().FullName;
action.ErrorMessage = ErrorMessage;
saveAction(action);
}
private void saveAction(MyActionsDataModel action) {
using (DbConnection connection = new SqlConnection(Constants.Connections.MyDatabase)) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
connection.Execute("UpdateAction", transaction: transaction,
commandType: CommandType.StoredProcedure, param: action);
transaction.Commit();
}
}
}
}
public interface IDbConnectionFactory {
DbConnection Create();
}
// Connection Factory method
public DbConnection Create() {
DbConnection connection = new SqlConnection(Constants.Connections.MyDatabase);
return connection;
}
public class MyHandlerType : HandlerBase
{
private readonly IDbConnectionFactory _connectionFactory;
public MyHandlerType(IDbConnectionFactory connectionFactory) : base(connectionFactory)
{
_connectionFactory = connectionFactory;
}
}
TEST:
public class HandlerTests
{
protected MyHandlerType _subjectUnderTest;
protected HandlerBase.IDbConnectionFactory _fakeConnectionFactory;
[SetUp]
public void Setup()
{
_fakeConnectionFactory = A.Fake<HandlerBase.IDbConnectionFactory>();
A.CallTo(() => _fakeConnectionFactory.Create()).Returns<DbConnection>(new SqlConnection(Constants.Connections.MyDatabase));
_subjectUnderTest = new MyHandlerType(_fakeConnectionFactory);
}
[TestCase]
public void Test_RecordFailure()
{
var innerMessage = "Throw AppException for UnitTest.";
var parentMessage = "Throw AggregationException for UnitTest.";
var innerException = new ApplicationException(innerMessage);
var parentException = new AggregateException(parentMessage, innerException);
_subjectUnderTest.RecordFailure(parentException);
var includeInnerMessage = testHandler.errorMessage.Contains(innerMessage);
var includeParentMessage = testHandler.errorMessage.Contains(parentMessage);
Assert.IsTrue(includeInnerMessage);
Assert.IsTrue(includeParentMessage);
}
}
I'm a beginner with C# MVC (about 6 months of self-learning), currently working on my first project, and I recently came across the problem of an SQL dependency duplicating when the user refreshes a page.
Through looking at various posts and articles across sites, I have cobbled together a working implementation, but I'm still getting my head around some of the elements of it, especially the singleton design pattern and the various class and property modifiers.
I would like to know, are there any gaping holes in my code, or any other considerations I should be making as I plan to set up a few more dependencies?
To give a bit of background to the project scale, it will be used by up to 500 users at a time, and the data affecting the dependency will change up to around once a second during busy periods.
Many thanks in advance. :)
Here is my dependency class:
public sealed class UMCSingleton
{
private static UMCSingleton instance;
private static string connString = ConfigurationManager.ConnectionStrings["ServerConnection"].ConnectionString;
private static SqlConnection conn = new SqlConnection(connString);
private SqlDependency dependency;
private static volatile object padlock = new object();
private UMCSingleton() {}
public static UMCSingleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new UMCSingleton();
}
}
}
return instance;
}
}
public static SqlConnection getUMCConnection()
{
try
{
if(conn == null)
{
conn = new SqlConnection(connString);
conn.Open();
return conn;
}
if(conn.State == ConnectionState.Closed)
{
conn.ConnectionString = connString;
conn.Open();
}
}
catch (SqlException e) {}
finally {}
return conn;
}
public void RegisterUnmanagdCallDependency()
{
using (getUMCConnection())
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT [CallRef], [CallLoggedByUserId] FROM [dbo].[UnplannedCustomers] Where [ServiceFlowId] = 1";
cmd.Notification = null;
if (dependency == null || dependency.HasChanges == true)
{
dependency = new SqlDependency(cmd);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
}
using (SqlDataReader reader = cmd.ExecuteReader()) {}
}
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e) //this will be called when any changes occur in db table.
{
if (e.Type == SqlNotificationType.Change)
{
SqlDependency dependency = (SqlDependency)sender;
if (dependency.HasChanges == true)
{
dependency.OnChange -= dependency_OnChange;
}
UnmanagedCallHub.ShowCalls();
RegisterUnmanagdCallDependency();
}
}
}
Here is my hub class:
public class UnmanagedCallHubData
{
public string CallRef { get; set; }
public string RaisedBy { get; set; }
}
public class UnmanagedCallHub : Hub
{
private ApplicationDbContext _context;
public UnmanagedCallHub()
{
_context = new ApplicationDbContext();
}
public static void ShowCalls()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<UnmanagedCallHub>();
context.Clients.All.UpdateCalls();
}
}
And finally my api controller:
public class UnmanagedCallController : ApiController
{
private ApplicationDbContext _context;
private UserProfile _uPro;
//CONSTRUCTOR SETS DB CONTEXT
public UnmanagedCallController()
{
_context = new ApplicationDbContext();
ApplicationUser user = HttpContext.Current.GetOwinContext()
.GetUserManager<ApplicationUserManager>().FindById(HttpContext.Current.User.Identity.GetUserId());
_uPro = _context.UserProfiles.SingleOrDefault(x => x.UserId == user.Id);
}
[HttpGet]
[Authorize]
public List<UnmanagedCallHubData> GetUnmanagedCalls()
{
List<UnmanagedCallHubData> calls = _context.UnplannedCustomers
.Where(x => x.ServiceFlowId == 1)
.Where(x => x.CurrentManagerUserId == null)
.Select(x => new UnmanagedCallHubData
{
CallRef = x.CallRef,
RaisedBy = x.CallLoggedByUserId
}).ToList();
UMCSingleton.Instance.RegisterUnmanagdCallDependency();
return calls;
}
}
I am implementing a command handler pattern and i want to create a composite command to solve some use cases. However to achieve this properly i need to resolve a delegate factory as described in http://docs.autofac.org/en/latest/advanced/delegate-factories.html.
However there is an additional complexity, it is generic ... So i assume it must be a generic delegate factory but I am not able to achieve this functionality. It looks complex, but I can not believe this functionality is not available in AutoFac.
I created a gist of my problem with a failing unit test at https://gist.github.com/robvanpamel/2aa2b27da8d0f922b9b98b6331b2e57f.
Is there anybody who could help me out?
using System;
using System.Collections.Generic;
using Xunit;
using Autofac;
namespace Tests
{
public class Tests
{
public class ClassUnderTest
{
public IContainer CreateContainer()
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterType<MyCommandHandler>().As<ICommandHandler<AnotherCommand>>();
builder.RegisterType<MyCommandHandler>().As<ICommandHandler<MyCommand>>();
builder.RegisterGeneric(typeof(CompositeCommandHandler<>)).As(typeof(ICommandHandler<>));
// How to register this ???
//builder.Register<Func<ICommand, ICommandHandler<ICommand>>>(c => s => c.Resolve(s)));
return builder.Build();
}
}
[Fact]
public void Test1()
{
// arrange
var myClassUnderTest = new ClassUnderTest();
var container = myClassUnderTest.CreateContainer();
var myCommand = new MyCompositeCommand(new List<ICommand> { new MyCommand(), new AnotherCommand() });
// act
Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<MyCommand>>());
Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<AnotherCommand>>());
var handler = container.Resolve<ICommandHandler<MyCompositeCommand>>();
handler.Handle(myCommand);
}
public interface ICommand { }
public interface ICompositeCommand : ICommand
{
IEnumerable<ICommand> Commands { get; }
}
public class MyCommand : ICommand { }
public class AnotherCommand : ICommand { }
public class MyCompositeCommand : ICompositeCommand
{
private readonly IEnumerable<ICommand> commands;
public MyCompositeCommand(IEnumerable<ICommand> commands)
{
this.commands = commands;
}
public IEnumerable<ICommand> Commands { get { return commands; } }
}
public interface ICommandHandler<T> where T : ICommand
{
void Handle(T command);
}
public class MyCommandHandler : ICommandHandler<MyCommand>, ICommandHandler<AnotherCommand>
{
public void Handle(MyCommand command)
{
Console.WriteLine("Handling MyCommand");
}
public void Handle(AnotherCommand command)
{
Console.WriteLine("Handling AnotherCommand");
}
}
public class CompositeCommandHandler<CompositeCommand> : ICommandHandler<CompositeCommand> where CompositeCommand : ICompositeCommand
{
private Func<ICommand, ICommandHandler<ICommand>> _factory;
public CompositeCommandHandler(Func<ICommand, ICommandHandler<ICommand>> factory)
{
_factory = factory;
}
public void Handle(CompositeCommand command)
{
foreach (var myCommand in command.Commands)
{
var handler = _factory(myCommand);
handler.Handle(myCommand);
}
}
}
}
}
At least I have found a sloution for this.
it isn't the best way i suppose but it is running.
using System;
using System.Collections.Generic;
using Xunit;
using Autofac;
using System.Reflection;
namespace Tests
{
public class Tests
{
public class ClassUnderTest
{
public IContainer CreateContainer()
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterType<MyCommandHandler>().As<ICommandHandler<AnotherCommand>>();
builder.RegisterType<MyCommandHandler>().As<ICommandHandler<MyCommand>>();
builder.RegisterGeneric(typeof(CompositeCommandHandler<>)).As(typeof(ICommandHandler<>));
return builder.Build();
}
}
[Fact]
public void Test1()
{
// arrange
var myClassUnderTest = new ClassUnderTest();
var container = myClassUnderTest.CreateContainer();
var myCommand = new MyCompositeCommand(new List<ICommand> { new MyCommand(), new AnotherCommand() });
// act
Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<MyCommand>>());
Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<AnotherCommand>>());
var handler = container.Resolve<ICommandHandler<MyCompositeCommand>>();
handler.Handle(myCommand);
}
public interface ICommand { }
public interface ICompositeCommand : ICommand
{
IEnumerable<ICommand> Commands { get; }
}
public class MyCommand : ICommand { }
public class AnotherCommand : ICommand { }
public class MyCompositeCommand : ICompositeCommand
{
private readonly IEnumerable<ICommand> commands;
public MyCompositeCommand(IEnumerable<ICommand> commands)
{
this.commands = commands;
}
public IEnumerable<ICommand> Commands { get { return commands; } }
}
public interface ICommandHandler<in T> where T : ICommand
{
void Handle(T command);
}
public class MyCommandHandler : ICommandHandler<MyCommand>, ICommandHandler<AnotherCommand>
{
public void Handle(MyCommand command)
{
Console.WriteLine("Handling MyCommand");
}
public void Handle(AnotherCommand command)
{
Console.WriteLine("Handling AnotherCommand");
}
}
public class CompositeCommandHandler<CompositeCommand> : ICommandHandler<CompositeCommand> where CompositeCommand : ICompositeCommand
{
private Func<ICommand, ICommandHandler<ICommand>> _factory;
private ILifetimeScope _container;
public CompositeCommandHandler(ILifetimeScope container)
{
_container = container;
}
public void Handle(CompositeCommand command)
{
foreach (var myCommand in command.Commands)
{
// resolve the specific command handler
var handler = ResolveMyHandler(myCommand);
// invoke the command handler
var handlerType = handler.GetType();
var handleMethod = handlerType.GetMethod(nameof(ICommandHandler<ICommand>.Handle),new []{myCommand.GetType()});
handleMethod.Invoke(handler, new[]{ myCommand});
}
}
public object ResolveMyHandler(ICommand command)
{
var mySpecificHandlerType = command.GetType();
var myGenericCommandHandlerType = typeof(ICommandHandler<>);
var result = myGenericCommandHandlerType.MakeGenericType(new[] { mySpecificHandlerType });
return _container.Resolve(result);
}
}
}
}
I'm using fluentvalidation and lightinject
Here is my code to insert a blog article;
public OperationResultDto Add(BlogArticleDto blogArticleDto)
{
OperationResultDto result = new OperationResultDto();
ValidationResult validationResult =
_blogArticleModelValidator.Validate(blogArticleDto);
if (!validationResult.IsValid)
{
result.IsOk = false;
ValidationFailure firstValidationFailer =
validationResult.Errors.FirstOrDefault();
if (firstValidationFailer != null)
{
result.Message = firstValidationFailer.ErrorMessage;
}
return result;
}
BlogArticle blogArticle = new BlogArticle {
Title = blogArticleDto.Title,
ShortBody = blogArticleDto.ShortBody,
Body = blogArticleDto.Body,
IsOnline = blogArticleDto.IsOnline,
CategoryName = blogArticleDto.CategoryName,
PublishedBy = blogArticleDto.PublishedBy,
PublishDate = blogArticleDto.PublishDate,
Tags = new List<string>(), //TODO parse, model's tags in one string.
CreateDate = DateTime.Now,
MainPhotoPath = blogArticleDto.MainPhotoPath,
};
_blogArticleRepository.Add(blogArticle);
return result;
}
As you can see, "validation section" is huge and I don't want to validate my dto parameters in my service(business) layer. I want to validate "arguments" in my ioc (lightinject).
Here is my ioc code to proceed that;
public class ServiceInterceptor : IInterceptor
{
public object Invoke(IInvocationInfo invocationInfo)
{
Log.Instance.Debug("Class: ServiceInterceptor -> Method: Invoke started.");
string reflectedTypeFullname = String.Empty;
string methodName = String.Empty;
if (invocationInfo.Arguments.Any())
{
//TODO Validate method parameters here..
foreach (object argument in invocationInfo.Arguments)
{
}
}
if (invocationInfo.Method.ReflectedType != null)
{
reflectedTypeFullname = invocationInfo.Method.ReflectedType.FullName;
methodName = invocationInfo.Method.Name;
}
... ...
Now, I can take all arguments of a method to give them to my fluentvalidator. So I know I need to define typeOf argument here but after that how can I call fluent validation's related validation object* to validate argument ?
I am the author of LightInject and maybe you could see if this example works out for you.
class Program
{
static void Main(string[] args)
{
var container = new ServiceContainer();
container.Register<AbstractValidator<Foo>, FooValidator>();
container.Register<IFooService, FooService>();
container.Intercept(sr => sr.ServiceType.Name.EndsWith("Service"), factory => new ServiceInterceptior(factory));
var service = container.GetInstance<IFooService>();
service.Add(new Foo());
}
}
public interface IFooService
{
void Add(Foo foo);
}
public class FooService : IFooService
{
public void Add(Foo foo)
{
}
}
public class Foo
{
}
public class FooValidator : AbstractValidator<Foo>
{
}
public class ServiceInterceptior : IInterceptor
{
private readonly IServiceFactory factory;
public ServiceInterceptior(IServiceFactory factory)
{
this.factory = factory;
}
public object Invoke(IInvocationInfo invocationInfo)
{
foreach (var argument in invocationInfo.Arguments)
{
Type argumentType = argument.GetType();
Type validatorType = typeof (AbstractValidator<>).MakeGenericType(argumentType);
var validator = factory.TryGetInstance(validatorType);
if (validator != null)
{
var validateMethod = validatorType.GetMethod("Validate", new Type[] { argumentType });
var result = (ValidationResult)validateMethod.Invoke(validator, new object[] { argument });
if (!result.IsValid)
{
//Throw an exception, log or any other action
}
}
}
//if ok, proceed to the actual service.
return invocationInfo.Proceed();
}
}
I am trying to refactor a piece of code which seems easily refactorable but is proving difficult. There are two method which seem very similar and I feel should be refactored:-
public class MyClass
{
private void AddBasicData(Receiver receiver)
{
var aHelper = new AHelper();
var bHelper = new BHelper();
var cHelper = new CHelper();
receiver.ObjA = aHelper.GetBasic();
receiver.ObjB = bHelper.GetBasic();
receiver.ObjC = cHelper.GetBasic();
}
private void AddExistingData(Receiver receiver)
{
var aHelper = new AHelper();
var bHelper = new BHelper();
var cHelper = new CHelper();
receiver.ObjA = aHelper.GetExisting();
receiver.ObjB = bHelper.GetExisting();
receiver.ObjC = cHelper.GetExisting();
}
}
The reference code for this class is here...
public class AHelper : Helper<A>
{
}
public class BHelper : Helper<B>
{
}
public class CHelper : Helper<C>
{
}
public class Helper<T> : IHelper<T> where T : IMyObj
{
public T GetBasic()
{
...
}
public T GetExisting()
{
...
}
}
public interface IHelper<T>
{
T GetBasic();
T GetExisting();
}
public class A : IMyObj {}
public class B : IMyObj {}
public class C : IMyObj {}
public interface IMyObj {}
public class Receiver
{
public A ObjA { get; set; }
public B ObjB { get; set; }
public C ObjC { get; set; }
}
My first attempt was to refactor like this...
public class MyClass
{
private void AddBasicData(Receiver receiver)
{
Func<Helper<IMyObj>, IMyObj> func = x => x.GetBasic();
AddData(receiver, func);
}
private void AddExistingData(Receiver receiver)
{
Func<Helper<IMyObj>, IMyObj> func = x => x.GetExisting();
AddData(receiver, func);
}
private void AddData(Receiver receiver, Func<Helper<IMyObj>, IMyObj> func)
{
var aHelper = new AHelper();
var bHelper = new BHelper();
var cHelper = new CHelper();
receiver.ObjA = func(aHelper);
receiver.ObjB = func(bHelper);
receiver.ObjC = func(cHelper);
}
}
The problem with this is objects like new AHelper() is not assignable to Helper<IMyObj> :-(
Can anyone see how this could be nicely refactored?
Thanks in advance
Russell
Try using a templated function. It should infer the type based on the type of parameter you pass, so you shouldn't need to explicitly specify the type in the AddData call.
public class MyClass
{
private void AddData<T>(Receiver receiver, Func<Helper<T>, T> func)
{
var aHelper = new AHelper();
var bHelper = new BHelper();
var cHelper = new CHelper();
receiver.ObjA = func(aHelper);
receiver.ObjB = func(bHelper);
receiver.ObjC = func(cHelper);
}
}
Attempt #2:
Tricky problem
I think you need a more generic IHelper interface. Would something like this help?
public interface IHelper
{
IMyObj GetBasic();
IMyObj GetExisting();
}
public interface IHelper<T> : IHelper
{
T GetBasic();
T GetExisting();
}
You'll have to work out the name conflict between the derived interface and the base interface, but I'm not sure exactly how you'd want to do that, and I'm running out of time, so I'll leave that as it for the moment.
Attempt #3 (I'm determined to get this!): Would this be cheating?
public enum RetrievalMethod
{
Basic,
Existing
}
public class Helper<T> : IHelper<T> where T : IMyObj
{
public T Get(RetrievalMethod rm)
{
switch(rm)
{
case RetrievalMethod.Basic:
return GetBasic();
case RetrievalMethod.Existing:
return GetExisting();
}
}
...
}
...
private void AddData(Receiver receiver, RetrievalMethod rm)
{
var aHelper = new AHelper();
var bHelper = new BHelper();
var cHelper = new CHelper();
receiver.ObjA = aHelper.Get(rm);
receiver.ObjB = bHelper.Get(rm);
receiver.ObjC = cHelper.Get(rm);
}
You can use casting for solving assigning problem. If AHelper actually return A, I think this works
private void AddData(Receiver receiver, Func<Helper<IMyObj>, IMyObj> func)
{
var aHelper = new AHelper();
var bHelper = new BHelper();
var cHelper = new CHelper();
receiver.ObjA = (A) func(aHelper);
receiver.ObjB = (B) func(bHelper);
receiver.ObjC = (C) func(cHelper);
}
if you override methods, you can do casting, dont need to change definition of "Func, IMyObj>"
public class AHelper : Helper<A>
{
public override A GetBasic()
{
return new A();
}
}
What about this?
private static T GetData<T, THelper>(Func<THelper, T> func)
where THelper : Helper<T>, new()
where T : IMyObj
{ return func(new THelper()); }
private static T GetBasicData<T, THelper>()
where THelper : Helper<T>, new()
where T : IMyObj
{ return GetData(x => x.GetBasic()); }
private static T GetExistingData<T, THelper>()
where THelper : Helper<T>, new()
where T : IMyObj
{ return GetData(x => x.GetExisting()); }
private void AddBasicData(Receiver receiver)
{
receiver.ObjA = GetBasicData<A, AHelper>();
receiver.ObjB = GetBasicData<B, BHelper>();
receiver.ObjC = GetBasicData<C, CHelper>();
}
private void AddExistingData(Receiver receiver)
{
receiver.ObjA = GetExistingData<A, AHelper>();
receiver.ObjB = GetExistingData<B, BHelper>();
receiver.ObjC = GetExistingData<C, CHelper>();
}