Get base class Member of controller in OnEntry in OnMethodBoundaryAspect in PostSharp - c#

I want access base class member in our Log Aspect Class. I have one base controller & that controller inherit by Test controller & in Test Controller i implemented AOP Aspect.
In BaseContoller i have a member _userSession. I initializing _userSession when BaseContoller's Constructor is call. And after call TestController first AOP Aspect is called. I want Access _userSession on OnEntry method of AOP.
LogAspect Class
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method)]
public class LogAspect:PostSharp.Aspects.OnMethodBoundaryAspect
{
public object UserData;
public override void OnEntry(PostSharp.Aspects.MethodExecutionArgs args)
{
LogManager.Info(string.Format("Starting - {0}-{0}",args.Instance, new StackTrace().GetFrame(1).GetMethod().Name));
// want access PCX.Portal.Controllers.BaseController._userSession member here its showing in quick watch like this
//((PCX.Portal.Controllers.BaseController)(args.Instance))._userSession
LogManager.Info(string.Format("User data - {0}", FrameworkHelper.Helper.JSONHelper.GetJSON(UserData)));
if(args.Arguments.Count>0)
{
foreach (var item in args.Arguments)
{
LogManager.Info(string.Format("arguments - {0}", FrameworkHelper.Helper.JSONHelper.GetJSON(item)));
}
}
base.OnEntry(args);
}
Base controller
public class BaseController : Controller
{
public UserSession _userSession { set; get; }
AuthenticationManager _authenticationManager = new AuthenticationManager();
public BaseController()
{
//initializing _userSession here
_userSession.userid=4 ;
_userSession.customerId=5 ;
}
}
Test Controller
[LogAspect]
public class TestController : BaseController
{
public ActionResult Index()
{
return View();
}
}

As documentation states:
MethodExecutionArgs class contains property Instance that:
Gets or sets the object instance on which the method is being executed.
as long as your method is not static you will get the object that is the this inside that method. Now you need to just cast it to BaseController as your property is public you will be able to access it.
if(args.Instance != null){
var baseController = (BaseController)args.Instance;
baseController._userSession
}
Although this is what you asked for I feel a need to remark that this approach limits your aspects usability to only instance methods of classes that inherit from BaseController. If you are able to create/retrieve form somewhere the session data in that parameterless constructor you can do it in aspect as well.

Related

Inject object to the constructor of controller using unity container

I couldn’t find any similar issue so I’m writing this post. There is sample controller with private field IBaseClass. Sample code looks like follows:
public class TmpController : Controller
{
private IBaseClass _baseClass;
public TmpController()
{
_baseClass = new BaseClass(this);
}
}
public interface IBaseClass
{
//...
}
public class BaseClass : IBaseClass
{
protected TmpController TmpController;
public BaseClass(TmpController tmpController)
{
TmpController = tmpController;
}
//IBaseClass implementation
}
My question is; how to inject BaseClass object to the constructor of TmpController using Unity framework?
I want to make my controller "slimmer". I want to put the logic about validation and preparing dataSource of my controls like comboBox etc. to different class. I try to make some kind of SOC in my .Web project in that very specific case, which will make my controller easier to read and maintain. I'm using approach one controller per one view but I met the case with very complex form. Currently I have controller with more than 3000 lines of code and it's hard to maintain so I want to do something with it.
And yes I'm using Services and Repositories but the problem is about validation of ViewModels, mapping ViewModel objects into DTOs and backwards, preparing data source of given components etc.
#Razem, what you guess from my comment is correct. And the minus point you described is also valid.
What you are asking "Service depending on the controller" can surely be achieved but that would be a bad design.
Currently BaseClass is only dependent on TempController. How would you handle the scenario when you need the BaseClass in some other controller also? The code will start breaking and you will end up adding new dependency to BaseClass.
Also as per the design recommendations Top Layers should be dependent on the Bottom Layers not the vice versa.
Being said that, you can still achieve the feature you are looking for that too by making controller dependent on the IBaseClass.
I am not sure the specific reasons you need to access controller inside BaseClass. I have made certain assumptions while creating following suggestions. One of such assumption is BaseClass, IBaseClass and Controller classes are part of the same assembly.
//Have a BaseController Class with the properties and/or method which you will be using in the `BaseClass` class and make them virtual so that derived controller classes can override them to have specific implementation.
public class BaseController : Controller
{
public virtual string ControllerMethod()
{
return "Controller Method from Base Controller";
}
public virtual string RandomValue
{
get
{
return "Random value from Base Controller";
}
}
}
Create a method in IBaseClass which will Set the Controller for it.
public interface IBaseClass
{
void SetController(BaseController controller);
void Method1();
}
public class BaseClass : IBaseClass
{
private BaseController controller;
public void SetController(BaseController controller)
{
this.controller = controller;
}
public void Method1()
{
var str = this.controller.RandomValue;
}
}
And derive the TempController from the BaseController and make it dependent on IBaseClass. And in the constructor of TempController call SetController method of IBaseClass by passing this argument to it. You also can override method/properties of BaseController here.
After this you can call any method of IBaseClass without passing controller instance to it.
public class TempController : BaseController
{
private IBaseClass baseClass;
public HomeController(IBaseClass productService)
{
this.baseClass = productService;
this.baseClass.SetController(this);
}
public override string RandomValue
{
get
{
return "Random value from Derived Class.";
}
}
public ActionResult Index()
{
this.baseClass.Method1();
ViewBag.Title = "Home Page";
return View();
}
}
Install nuget package Unit.Mvc in your web project. Open file Unity.Config located under App_Start folder and change method RegisterTypes as following.
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IBaseClass, BaseClass>(new PerRequestLifetimeManager());
}
I am sure I don't need to explain how this is going to work.
P.S. : You need to make sure that you calls IBaseClass.SetController method in controller constructor to avoid NullReferenceException when you use controller in BaseClass. This is small overhead you need to take to achieve good and maintainable design.

Set the type of registered Service during runtime within an action filter/message handler

public class ActionFilterVersionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Any(x => x.Key == "SetInternalVersion"))
{
// determine somehow that the **InternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
else
{
// determine somehow that the **ExternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
base.OnActionExecuting(actionContext);
}
}
I have ExternalSystem/InternalSystem with the ISystem interface.
How can I tell autofac to inject the ExternalSystem or InternalSystem into the instantiated controller as ISystem instance depending on the string value I pass in the ActionFilter or maybe message handler.
I know I can do stuff like:
builder.RegisterType<InternalSystem>().As<ISystem>().Keyed<ISystem>("Internal");
where I can use a func<string,ISystem> factory to resolve the class during runtime but this is not what I want to do.
Actually I need to register the ISystem within the the action filter, but then I would need somehow to pass the container into the filter, but that is not what I want...and prolly its also not possible.
// Action: returns external or internal value
public string Get()
{
return resolvedISystem.Get();
}
Of course I could resolve the ISystem depending on the func factory within each single action or put behavior into a base controller where I check for the header, but I really would prefer the action filter as it can be just globally registerd ONE time, but for each new controller I have to subclass the base controller.
Base controller sample with pseudo code , because the base.Request is null which needs another workaround/fix...
public class BaseController : ApiController
{
public BaseController(Func<string, ISystem> dataServiceFactory)
{
string system = base.Request.Headers.Any(x => x.Key == "SetInternalVersion") ? "internal" : "external";
System = dataServiceFactory(system);
}
public ISystem System { get; set; }
}
UPDATING the container is also marked as OBSOLETE by the Autofac author.
Thus I do not want to add registrations in my filter/handler and update/build the container again.
I think you should not use ActionFilter at all. You have a controller dependency which should be resolved properly based on the information coming from request. Here is a possible solution. You can use a static HttpContext.Current property in order to extract request header.
System classes:
public interface ISystem { }
public class ExternalSystem : ISystem { }
public class InternalSystem : ISystem { }
SystemKeyProvider:
public enum SystemKey
{
External,
Internal
}
public interface ISystemKeyProvider
{
SystemKey GetSystemKey();
}
public class SystemKeyProvider : ISystemKeyProvider
{
private const string HeaderKey = "SetInternalVersion";
private readonly HttpRequest _request;
public SystemKeyProvider(HttpRequest request)
{
_request = request;
}
public SystemKey GetSystemKey()
{
return (_request.Headers[HeaderKey] != null) ?
SystemKey.Internal :
SystemKey.External;
}
}
Controller constructor: ValuesController(ISystem system)
Autofac container registration:
var builder = new ContainerBuilder();
builder.Register(c => HttpContext.Current.Request).As<HttpRequest>().InstancePerRequest();
builder.RegisterType<SystemKeyProvider>().AsImplementedInterfaces();
// service registration
builder.RegisterType<ExternalSystem>().Keyed<ISystem>(SystemKey.External);
builder.RegisterType<InternalSystem>().Keyed<ISystem>(SystemKey.Internal);
builder.Register(c =>
c.ResolveKeyed<ISystem>(c.Resolve<ISystemKeyProvider>().GetSystemKey()))
.As<ISystem>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(builder.Build());
In this solution I created a SystemKeyProvider wrapper class which is responsible for providing appropriate key in order to resolve ISystem.
Demo:
When no SetInternalSystem header is present.
Then the dependency is resolved as ExternalSystem.
When SetInternalSystem header is present.
Then the dependency is resolved as InternalSystem.

Unit testing non-public methods in dotnet core controller

Suppose in an MVC5 controller I had a method in my controller that gets called by other methods in the controller, but I don't want it available to a user. If I wanted to be able to mock it, it would look like this:
[ChildActionOnly]
public virtual string DoSpecialFormatting(string mySpecialString)
{
// stuff
}
Or I could have tossed [assembly: InternalsVisibleTo("MyLittleProject.Tests")] and [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] (for Moq) into AssemblyInfo.cs and marked the method as internal instead of public:
internal virtual string DoSpecialFormatting(string mySpecialString)
{
// stuff
}
Now that there is no ChildActionOnly and I don't see an AssemblyInfo.cs file in my new ASP.NET Core project, how would I have methods in my controller class which web users cannot access but can still be mocked?
In ASP.NET Core the attribute is called NonActionAttribute.
[NonAction]
public virtual string DoSpecialFormatting(string mySpecialString)
{
// stuff
}
Imho its better than internal.
You can extract that method to a class , i.e. named SpecialFormatter, and inject to the controller via DI. To test your controller you can mock this class.
class SpecialFormatter
{
public string DoSpecialFormatting(string mySpecialString)
{
// stuff
}
}
Then in your controller
class SomeController : Controller
{
private SpecialFormatter _formatter;
public SomeController(SpecialFormatter formatter)
{
_formatter = formatter;
}
public ActionResult SomeAction(string input)
{
string output = _formatter.DoSpecialFormatting(input);
// stuff
}
}

How to call parameterized constructor controller action in another controller?

I am having two controller. 1st controller having parameterized constructor and some methods. Now I have to call that methods in my another controller. is there any way to do it?
Below is code
public partial class oneController : Controller
{
private readonly IEmployeeService _employeeService;
public oneController(IEmployeeService employeeService)
{
this._employeeService = employeeService;
}
// some methods
}
public partial class twoController : Controller
{
// Need to call some methods from oneController
}
You can achieve this as follow:
public partial class twoController : Controller{
oneController one = new oneController();
one.AnyMethod(AnyParam);
}
But you're trying to do something the controllers aren't designed for. if you have some common method which is being accessible from multiple controllers then create required method as an public method in some class and invoke from any controller/actions you want.

Routing from one view to another controller's action method and passing a parameter to that controller's constructor

I'm creating my first C# MVC site and quite early on I've hit a roadblock where I'm not sure if I'm going about things entirely the wrong way and I can't find an example similar to my own online but it seems like what I'm trying to do should be straightforward.
Basically, I have my initial controller (called ClientController) that sets up a list of clients and then displays them in my list view:
public class ClientController : Controller
{
private readonly IClientManagerRepository _clientManagerRepository;
public ClientController()
: this(new EntityClientManagerRepository())
{
}
public ClientController(IClientManagerRepository repository)
{
_clientManagerRepository = repository;
}
//
// GET: /Client/
public ViewResult List()
{
return View(_clientManagerRepository.GetAllClients());
}
}
Then in my view I have an action link where I want to route to my UserController, passing it the client name, so that it can build the list of users for that particular client.
#Html.ActionLink("View Admin Users","Index","User",new {clientName = item.ClientName},null)
This works with the following code:
public class UserController : Controller
{
private IUserManagerRepository _userManagerRepository;
//
// GET: /User/
public ActionResult Index(string clientName)
{
_userManagerRepository = new EntityUserManagerRepository(clientName);
return View(_userManagerRepository.GetAllUsers());
}
}
And my list of users is displayed correctly in my view.
However, when I then add in my details action method it doesn't work because the _userManagerRepository isn't instantiated:
//
// GET: /User/Details/5
public ActionResult Details(int contactId)
{
return View(_userManagerRepository.GetUser(contactId));
}
I would have to I guess pass in the clientname each time and re-instantiate my _userManagerRepository. That doesn't feel like a very good way though.
Ideally I'd like to create my _userManagerRepository in the constructor of my UserController. I've been looking into how I would do this so I'd have something like:
public class UserController : Controller
{
private IUserManagerRepository _userManagerRepository;
public UserController(string clientname)
: this(new EntityUserManagerRepository(clientname))
{
}
public UserController(IUserManagerRepository repository)
{
_userManagerRepository = repository;
}
I've researched that I can create my own controller factory so that I can have a parameter in my userController constructor however I still don't understand how I would pass my clientname parameter form a view to my UserController.
If you want to instantiate Repository class in controller's constructor,you can use NInject,
it's really nice approach to do it.
1-Install Ninject from Nuget
2-Create Repository Abstract for example ICustomerRepository
public abstract ICustomerRepository
{
string GetCustomerName();
}
3-Create Repository for example CustomerRepository
public class CustomerRepository:ICustomerRepository
{
string GetCustomerName()
{
return ("John");
}
}
4-create CustomerControllerFactory Class
public class CustomControllerFactory : DefaultControllerFactory
{
private static IKernel ninjectKernel;
public CustomControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings(ninjectKernel);
}
protected override IController GetControllerInstance
(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return (new Controllers.MessageController());
}
else
{
return ((IController)ninjectKernel.Get(controllerType));
}
}
public static void AddBindings(IKernel ninjectKernel)
{
Common.DependencyInjection.DependencyManager.GetDependencyInjections().ForEach(current =>
{
if (current.Abstract != null && current.Implementation != null)
{
ninjectKernel.Bind(current.Abstract).To(current.Implementation);
}
});
ninjectKernel.Bind<ICustomerRepository>().To(typeof(CustomerRepository));
}
}
ninjectKernel.Bind().To(typeof(CustomerRepository));
I bind ICustomerRepository to CustomerRepository in upper code
5- Add below code to Application_Start
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
6-Create New Controller
public class CustomerController:Controller
{
public CustomerController(ICustomerRepository customerRepository)
{
//customerRepository instantiate to CustomerRepostory Class automatically
}
}
it's Dependency Injection that i think useful for you
Regards

Categories