Is it possible to statically access the current controller? - c#

Out of pure curiosity, is it possible to access the current controller from a static context while it is being executed with the current HttpRequest/Action?

No, this is not possible from a static context because many different controllers could be executing at some given point of time for multiple concurrent requests.

I don't know of a way to do it statically but what I do for this while handling some session/authentication management I have all my controllers inherit from a custom BaseController class that inherits from the System.Web.Mvc.Controller class. In the Base Controller class I override the OnActionExecuted method.
public class BaseController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Your logic here
base.OnActionExecuted(filterContext);
}
}
public class HomeController : BaseController
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}

Related

OnActionExecution on BaseController and Particular Controller

I have a BaseController which is like below.
public class BaseController : Controller
{
public string BDynamicConnectionString { get; set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Getting dynamic connectionstring
this.BDynamicConnectionString = GetDynamicConnetionString(this.BCCompanyId, this.BCCompanyIdentifier);
}
}
I have inherited this base controller in my controller as below.
public class TestController : BaseController
{
private ClassroomBL objClassroomBL;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
this.objClassroomBL = ClassObjects.ClassroomBLObject(BDynamicConnectionString);
}
public ActionResult FetchDefaultStatuses()
{
this.objClassroomBL.FetchDefaultStatuses(145);
return View();
}
}
As it is visible I have OnActionExecuting(ActionExecutingContext filterContext) on both BaseController and TestController.
Actually Why I did it like this is I am managing many things in base controller which are needed in each controller inherited from this.
But now I need something like OnActionExecuting(ActionExecutingContext filterContext) on particular controller because I have to initialize object before calling action and object which I have to initialize it uses a property which is initialized in BaseController.
If I am adding OnActionExecuting(ActionExecutingContext filterContext) on both then first, controller which is inheriting BaseController on this event fires before the BaseController. I know this happening because of OOPS concept.
Is anything else I can add on Controller which fires after Basecontrollers OnActionExecuting but before action execution of particular controller .
Thanks!
Just use following in the first line of overrided method:
base.OnActionExecuting(filterContext)
See also base keyword.

.net core routing, understand what application called with a generic route

So what I have is a base controller that the following [Route] definition
[Route("{application}/api/[controller]")]
public class BaseController
{
}
All of my current controllers inherit from BaseController.
What I am trying to achieve is that two different application can call my controllers and my code to be aware of what 'application' is calling it.
Application 1 should be able to call /Application1/Api/MyController
Application 2 should be able to call /Application2/Api/MyController
and both requests should go to the same controller but my code should be aware of which application called it.
I thought about having some sort of Middleware and then work out the application from the Request.Path, and then store it in something like HttpContext.Current.Items but that doesn't seem like the correct way to do it.
My personal preference here would be to pass the value as an HTTP header rather than a route parameter, especially if you want it everywhere. It means you don't need a Route attribute and a different URL per application. Using a custom ActionFilterAttribute, there's a bunch of ways you can pass this detail into your action. For example:
public class ApplicationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.HttpContext.Request.Headers.TryGetValue("Application", out var values))
{
// Method 1: This allows you to specify a parameter on your action
context.ActionArguments.Add("application", values.First());
// Method 2: This adds the value into the route data
context.RouteData.Values.Add("Application", values.First());
// Method 3: This will set a property on your controller
if (context.Controller is BaseApplicationController baseController)
{
baseController.Application = values.First();
}
}
base.OnActionExecuting(context);
}
}
And apply it to action methods or your controller:
[Application]
public class FooController : Controller
{
}
Method 1 Usage:
public IActionResult Index(string application)
{
// do something with the parameter passed in
}
Method 2 Usage:
public IActionResult Index(string application)
{
var application = (string)RouteData.Values["Application"];
}
Method 3 Usage:
First, create a base controller that contains the property:
public abstract class BaseApplicationController : Controller
{
public string Application { get; set; }
}
Then make sure your controller inherits from it:
[Application]
public class FooController : BaseApplicationController
{
}
Now you can access the property on your controller:
public IActionResult Index(string application)
{
var application = this.Application;
}
Bonus Method 4:
As an aside, you could use this method to use the URL route value, using the base controller from method 3, modify the attribute to look like this:
public class ApplicationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.Controller is BaseApplicationController baseController)
{
baseController.Application = (string)context.RouteData.Values["application"];
}
base.OnActionExecuting(context);
}
}
Add a route attribute to your controller:
[Route("{application}/api/[controller]/[action]")]
And now you should have the property value on the controller set.
You could move the route template into action and then each action would technically be aware of its caller context by your proposed convention:
[Route("api/[controller]")]
public class YourController : BaseController
{
[HttpGet("{application}")]
public IActionResult Get(string application)
{
if (application == "Application1")
{
...Application1 called
}
if (application == "Application2")
{
...Application2 called
}
...
}
}
Of course, this is your proposed convention and it is not enforced through some custom application authentication in any way so you will have to trust that your callers will correctly identify themselves through this convention.
Another approach, could be to have a base class variable and set that after inspecting the route.
[Route("{application}/api/[controller]")
public class BaseController: Controller
{
protected string CallingApp { get; set; }
public override void OnActionExecuting(ActionExecutingContext ctx)
{
CallingApp = ctx.RouteData.Values["application"];
base.OnActionExecuting(ctx);
}
}

Dotnet Core MVC - Apply action filter to specific controllers only

I have worked in MVC on .Net 4 and I had my action filters overridden in the controller class. That way I can have multiple controllers, each with a unique OnActionExecuting method.
Now I'm working on Dotnet Core 2.1 and things are a little different so I can't get the same methodology to work.
I have a controller for an API that inherits ControllerBase and then another controller for serving pages, that one inherits Controller.
I created my action filter class that derives from ActionFilterAttribute.
I then registered my action filter by using this line:
services.AddMvc(config => { config.Filters.Add(typeof(MyActionFilter)); })
The problem is that the filter now applies to the API controller as well as the pages controller. Is there a way the action filter can be applied to specific controllers only?
I used this page as a reference for my initial action filter implementation.
I know that inside the OnActionExecuting method I can use context.Controller.GetType() to compare it to the types of my individual controllers, but I would prefer to avoid that, and instead specify which controllers should use which action filters.
Thanks in advance.
services.AddMvc(config => { config.Filters.Add(typeof(MyActionFilter)); })
The above source code is used when you want to apply the global filter that mean every API will have the affected.
So to specific particular Controller you just simply add [MyActionFilter] atribute to you controller
Example:
[MyActionFilter]
public class HomeController : Controller {
public ViewResult Index(){..}
}
First of All Register Your filter in your startup.cs
services.AddScoped<"---FilterNameHere----">();
Put Your Filter in controller like
[ServiceFilter(typeof("----FilterNameHere---"))]
public class HomeController : ControllerBase
{
public IActionResult Index()
{//do your code here}
}
Was looking for an answer too. Both above confused me. Went to the page of the documentation...
Two ways of doing this in a clean way.
An action filter for all actions of all controllers.
public class YourActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
throw new System.NotImplementedException();
}
public void OnActionExecuting(ActionExecutingContext context)
{
throw new System.NotImplementedException();
}
}
And in startup do
services.AddControllers(c => { c.Filters.Add(new YourActionFilter()); })
An Attribute that you want to use only on specific actions which implements TypeFilterAttribute and has an private class that implemements an action filter.
public class YourActionFilterAttribute : TypeFilterAttribute
{
public YourActionFilterAttribute() : base(typeof(TheActionFilter)) { }
private class TheActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
throw new System.NotImplementedException();
}
public void OnActionExecuting(ActionExecutingContext context)
{
throw new System.NotImplementedException();
}
}
}
Now you only need to add it to a whole controller or to a specific action
[YourActionFilter]
public class HomeController : ControllerBase
{
[YourActionFilter]
public IActionResult Index()
{//do your code here}
}

c# .net access parent obj

I am using .net c# MVC controller to query database for many of my projects. Every time i create a new controller, I find myself having to rewrite some of the same function for the new controller hence, I thought about writing a basic controller to handle some of the basic task that I use in all my controller (e.g., run a query and run json).
In my controller, I reference the basic controller like this.
namespace myWebAPI.Controllers
{
public class esrcController : Controller
{
//
// GET: /esrc/
string db = "esrc-";
basicController BasicController = new basicController();
public string test()
{
return "test" + Request.ServerVariables["HTTP_REFERER"];
}
public string getCodingException()
{
return #"{""data"":" + BasicController.getDataNconvertToJSON(
"select * from z_codingexception order by nc_key",
BasicController.getEnviroment(db)) + "}";
}
}
}
in my BasicController, the getEnviroment looks at the url to determine the environment hence I need access to :
Request.ServerVariables["HTTP_REFERER"] and Request.ServerVariables["HTTP_HOST"].ToString().ToLower();
but Request is null in this controller, I only have access to request in the main controller. How do I reference httpRequest from basic controller?
Just because you instantiate a new instance of a controller, doesn't mean you'll have access to the context.
One option is to create an abstract base controller that all of your other controlers would inherhit from. You'll then have access to the specific objects like Request
WebApiConfig.cs
config.MapHttpAttributeRoutes();
Your Controller
public abstract class MyBaseController : Controller
{
protected void myMethod()
{
// you have access to Request here
}
}
public class MyController : MyBaseController
{
[HttpGet]
[Route("my/getstuff")]
public IHttpActionResult GetStuff()
{
// do stuff
base.myMethod();
return Ok();
}
}
Create an action filter and add it as an attribute to that class. Within the action filter yuo wil have access to the Request object. If you override the OnActionExecuting function, the functionality in your filter will be executed before your controller.
Create a custom filter
public class CustomAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//DO STUFF WITH YOUR REQUEST OBJECT HERE..
}
}
Add the filter as an attribute to your controller
[CustomAttribute]
public class esrcController : Controller

ASP MVC ActionFilterAttribute OnActionExecuting not fired

I have 2 controllers Home with
public class HomeController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// do some irrelevant stuff
base.OnActionExecuting(filterContext);
}
public ActionResult Index()
{
return View();
}
}
and Service with
public ActionResult Confirm()
{ return RedirectToAction("Index", "Home");}
And one ActionFilterAttribute with OnActionExecuting method
public class InvitationModeAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// do some stuff
base.OnActionExecuting(filterContext);
}
}
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new InvitationModeAttribute());
}
}
When I go to localhost/Service/Confirm , OnActionExecuting is fired, but then when RedirectToAction is called, OnActionExecuting is not fired.
How can I catch this after RedirectToAction?
Thanks
Refer this For More clarity
First of all
Remove OnActionExecuting method in controller level
public class HomeController : Controller
{
[InvitationModeAttribute]
public ActionResult Index()
{
return View();
}
}
2nd Controller
public class ServiceController : Controller
{
[InvitationModeAttribute]
public ActionResult Confirm()
{
return RedirectToAction("Index", "Home");
}
}
From MSDN
Scope of Action Filters
In addition to marking individual action methods with an action
filter, you can mark a controller class as a whole with an action
filter. In that case, the filter applies to all action methods of that
controller. Additionally, if your controller derives from another
controller, the base controller might have its own action-filter
attributes. Likewise, if your controller overrides an action method
from a base controller, the method might have its own action-filter
attributes and those it inherits from the overridden action method. To
make it easier to understand how action filters work together, action
methods are grouped into scopes. A scope defines where the attribute
applies, such as whether it marks a class or a method, and whether it
marks a base class or a derived class.

Categories