I want to show some dialogs from a static class, and I cannot figure out how can I access to the DialogService object that is injected into the viewmodels. Is there any way I can get it?
For the NavigationService, I expose the property in my App.xaml.cs and I can get it from everywhere in my app. I would like to do the same with the DialogService, but I can't do it like this because I don't see the service in the app.xaml.cs.
This is how do it in my App.xaml.cs for the NavigationService:
public INavigationService oNavigationService => NavigationService;
I want to show some dialogs from a static class
You don't want to do that. That static thing. What you want is a regular (non-static) class registered as singleton. This way you get injected dependencies and your problem becomes trivial.
Like:
internal class ThisWasStaticBefore
{
public ThisWasStaticBefore( INavigationService navigationService )
{
_navigationService = navigationService;
}
public void DoStuff()
{
_navigationService.Navigate();
}
private readonly INavigationService _navigationService;
}
and in your Application-class:
protected void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<ThisWasStaticBefore>();
}
and somewhere else
internal class SomeConsumer
{
public SomeConsumer( ThisWasStaticBefore theService )
{
_theService = theService;
}
public void DoStuff()
{
_theService.DoStuff();
}
private readonly ThisWasStaticBefore _theService;
}
Side-note:
If you insist, you can do it the wrong way and keep your class static and access the service by ContainerLocator.Container.Resolve<INavigationService>()...
Related
All classes that inherit from controller have already inserted the dependencies, but I do not know how to inject those who do not inherit from contoller.
in the example below the SendEmailAndLog() method waits for the ILoggerService interface to be injected. but I do not know how to do this.
public async Task Execute(IJobExecutionContext context)
{
SendEmailHelper sendEmailHelper = new SendEmailHelper();
await sendEmailHelper.SendEmailAndLog(user, "Task", user.UserName, UserManager, loggerService);
}
this task is called the method Application_Start() on Global.asax.cs
I created a constructor to receive this service as a parameter, this is working for the methods within the controllers that call the Class Emailservice. However there are classes that do not inherit from controller so I do not know how to inject.
My Service is:
public interface ILoggerService
{
void Error(ExceptionLogger exception);
void SaveLog();
}
public class LoggerService : ILoggerService
{
private readonly ILoggerRepository loggerRepository;
private readonly IUnitOfWork unitOfWork;
public LoggerService(ILoggerRepository loggerRepository, IUnitOfWork unitOfWork)
{
this.loggerRepository = loggerRepository;
this.unitOfWork = unitOfWork;
}
public void Error(ExceptionLogger exception)
{
loggerRepository.Error(exception);
}
public void SaveLog()
{
unitOfWork.Commit();
}
}
I have a problem with the Automapper on my website and I can't find a solution.
I've created a class called AutoMapperProfile where I'd like to put all my Maps
public class AutoMapperProfile: Profile
{
private readonly IConfiguration _mapper;
public AutoMapperProfile(IConfiguration mapper)
{
_mapper = mapper;
}
protected override void Configure()
{
base.Configure();
_mapper.CreateMap<SlideDTO, Slide>();
_mapper.CreateMap<Slide, SlideDTO>();
}
}
For DI purposes I'm using Ninject, so I've added the following bindings in NinjectWebCommon:
kernel.Bind<IMappingEngine>().ToMethod(ctx => Mapper.Engine);
kernel.Bind<IConfigurationProvider>().ToMethod(x => Mapper.Engine.ConfigurationProvider);
The controller looks like this:
private readonly ISlideRepository slideRepository;
private readonly IMappingEngine mappingEngine;
public HomeController(
ISlideRepository slideRepository,
IMappingEngine mappingEngine)
{
this.slideRepository = slideRepository;
this.mappingEngine = mappingEngine;
}
[HttpGet]
public ActionResult Index()
{
var model = new IndexViewModel();
var slide = slideRepository.GetSlide();
model.Slide = mappingEngine.Map<SlideDTO, Slide>(slide);
return View(model);
}
When I map from SlideDTO to Slide I get the following error:
Missing type map configuration or unsupported mapping.
So my best guess is that I didn't do the binds correctly so that Automapper can see my maps, but I'm not sure how can I fix it.
You don't need to inject IConfiguration into AutoMapperProfile, it already inherits a CreateMap method from Profile.
Make sure that AutoMapperProfile has a parameterless constructor like this:
public class AutoMapperProfile : Profile
{
protected override void Configure()
{
this.CreateMap<SlideDTO, Slide>();
this.CreateMap<Slide, SlideDTO>();
}
}
And then you need to make sure that AutoMapper knows about this profile, here is how you can do it:
Mapper.Engine.ConfigurationProvider.AddProfile<AutoMapperProfile>();
Please note that you can invoke the AddProfile method on any IConfigurationProvider (if you decide not to use the global ConfigurationProvider and Engine).
public abstract class MyControllerBase : Controller
{
protected override void OnActionExecuting(ActionExecutingContext context)
{
// do some magic
}
}
All of my controllers inherit from MyControllerBase. The problem is that now I can't unit test certain methods because the filter sets some authorisation/logic flags which influence code path.
Is there any way to manually trigger OnActionExecuting? How does the pipeline trigger these events?
EDIT: to show a little more the idea behind this design in response to comments. I basically have something like this:
public abstract class MyControllerBase : Controller
{
protected override void OnActionExecuting(ActionExecutingContext context)
{
UserProperties =
_userService
.GetUserProperties(filterContext.HttpContext.User.Identity.Name);
ViewBag.UserProperties = UserProperties;
}
public UserProperties { get; private set; }
public bool CheckSomethingAboutUser()
{
return UserProperties != null
&& UserProperties.IsAuthorisedToPerformThisAction;
}
// ... etc, other methods for querying UserProperties
}
So now anywhere in View or Controller I can get details of the current user, what is their email, what authorisation they have, which department they work for etc.
Example:
public class PurchasingController : MyControllerBase
{
public ActionResult RaisePurchaseOrder(Item item)
{
// can use UserProperties from base class to determine correct action...
if (UserProperties.CanRaiseOrders)
if (UserProperties.Department == item.AllocatedDepartment)
}
}
So this design works really nice, but as you can see testing the above action is difficult as I can't directly manipulate the UserProperties in the test set up.
I'm not sure you're suppose to override OnActionExecuting like that in MCV, normally I make an ActionFilterAttribute
public class SomeMagicAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
}
}
Then your class:
[SomeMagic]
public abstract class MyControllerBase : Controller
{
}
Then in your unit test you can just do
var magic = new SomeMagicAttribute();
var simulatedContext = new ActionExecutingContext();
magic.OnActionExecuting(simulatedContext);
I am using unity, entity framework 4 with POCO classes, repository pattern for DAL and services for Business Logic control.
I also want to use Unit of Work so I can package together CRUD operations which I perform on different services and then commit them all together.
My question is what would be the proper way to inject the Unit Of Work mechanism into my application using Microsoft Unity?
I understand that I can put the IUnitOfWork together with the repository on the constructor of the proper service and then if Unity mapping is specified it would auto initiate the proper instances, but this way I do not pass the global unit of work but rather create a new instance on each level, which can't be a smart way to do it (actually the repository is initiated even before the service).
What am I missing? (Attached is constructor code as I wrote it now of service and its repository).
U also understand that I can use Unity's ParameterOverrides method to take some global instance of Unit of Work (lets say from my aspx.cs file) and pass it into the service and then into the repository. But it seems a bit lame. Is this my only option?
Thanks
public class GenericRepository<T> : IUnitOfWorkRepository, IGenericRepository<T> where T : BaseEntity, IAggregateRoot
{
private IUnitOfWork _uow;
/// <summary>
/// Returns the active object context
/// </summary>
private ObjectContext ObjectContext
{
get
{
return ObjectContextManager.GetObjectContext();
}
}
public GenericRepository(IUnitOfWork uow)
{
_uow = uow;
}
//blahhhh...
public void Add(T entity)
{
_uow.RegisterNew(entity, this);
}
public void Delete(T entity)
{
_uow.RegisterRemoved(entity, this);
}
//.....blah blah....
public void PersistCreationOf(IAggregateRoot entity)
{
this.ObjectContext.AddObject(GetEntitySetName(), entity);
}
public void PersistUpdateOf(IAggregateRoot entity)
{
// Do nothing as EF tracks changes
}
public void PersistDeletionOf(IAggregateRoot entity)
{
this.ObjectContext.DeleteObject(entity);
}
}
public class CategoryRepository : GenericRepository<XComSolutions.FB.Domain.Model.Entities.Category>, ICategoryRepository
{
public CategoryRepository(IUnitOfWork uow)
: base(uow)
{ }
}
public class CategoryService : ICategoryService
{
public int myID {get; set;}
private ICategoryRepository _categoryRepository;
private IUnitOfWork _uow;
public CategoryService(ICategoryRepository categoryRepository,
IUnitOfWork uow)
{
_categoryRepository = categoryRepository;
_uow = uow;
}
public List<Category> GetAll()
{
return _categoryRepository.GetAll();
}
}
Define an IUnitOfWorkFactory and inject that in your services:
public class Service
{
private readonly IUnitOfWorkFactory factory;
public Service(IUnitOfWorkFactory factory)
{
this.factory = factory;
}
public void DoOperation()
{
using (UnitOfWork context = this.factory.CreateNew())
{
this.DoSomeStuff(context);
this.DoMoreStuff(context);
context.SubmitChanges();
}
}
}
What I think you need to do is to define unit of work factory. You register this factory with your DI container and you resolve for this factory every time you need your unit of work. Then you get unit of work from the factory, work with it and let it go. You often will see that you need your unit of work within a scope of single method or single class. This article discuss Unit of Work pattern in connection with Entity Framework: http://msdn.microsoft.com/en-us/magazine/dd882510.aspx
I'm trying to add logging with aspect orientated programming using castle windsor in plain asp.net, i.e. not MVC
I've added a class that implements the IInterceptor interface and an attribute that inherits from Attribute.
public class LogAttribute : Attribute
{
public Level LogLevel { get; set; }
public LogAttribute(Level level)
{
LogLevel = level;
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
MethodInfo mi = invocation.Method;
LogAttribute[] atts = (LogAttribute[])mi.GetCustomAttributes(typeof(LogAttribute), true);
// if method not marked with InternalUseRestricted attribute, then pass on call
if (atts.Length == 0)
{
invocation.Proceed();
}
else
{
ISeiLogger log = LoggerFactory.GetLogger(mi.DeclaringType.ToString());
//assume only one logging attribute
//log on entry
log.LogEnter(atts[0].LogLevel);
//allow code to continue
invocation.Proceed();
//log on exit
log.LogExit(atts[0].LogLevel);
}
}
}
Now in the global.asax.cs I've added the following:
public partial class Global : System.Web.HttpApplication, IoCProvider
{
private void InitializeIoC()
{
container = new WindsorContainer();
container.Install(new Sei.Aspect.AspectInstaller());
}
public IWindsorContainer Container
{
get { return container; }
}
private static Sei.Logging.ISeiLogger log;
private IWindsorContainer container;
public override void Init()
{
base.Init();
InitializeIoC();
}
and I've created an installer class:
public class AspectInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IInterceptor>().Configure(component => component.LifeStyle.PerWebRequest));
container.Register(Component.For<IInterceptor>().ImplementedBy<LoggingInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<InternalUseRestrictedInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<CachingInterceptor>().LifeStyle.PerWebRequest);
}
}
I now want to add the attribute to some arbitary page's code behind class and some arbitary virtual method, as in
[Log(Level.Info)]
protected string Login(string username, string password)
{
DoSomething();
}
This obviously doesn't work. Do I need to change the way I'm instantiating the page (its a page's code-behind class) to use a container? Or is it the way I'm registering the interceptors? I want to be able to use the interceptors on any class going forward and not have to tell the container about each and every class that I have in my application.
Short answer: it's not possible.
Long answer: due to the way ASP.NET Web Forms works, it doesn't let anyone interfere with the page instantiation. Some claim that using a custom PageHandlerFactory lets you do IoC, but this only lets you set properties after the page has been instantiated, which is simply not enough for proxying.
So runtime proxy libraries such as DynamicProxy or LinFu can't do anything about this. But you may be able to use compile-time aspect weavers, such as PostSharp.
Alternatively, make your code-behind as slim as possible, deferring actual logic to Windsor-managed components.