I have two different controller --> Controller A,Controller B
And I have different methods each controller and their return values IHttpActionResult (Method A controller A ,Method B and Controller B)
How can I access another controller method and take its content from another controller
Controller B ,and Inside Method B
IHttpActionResult result = ControllerA.MethodA()
and I want to read result.content inside controller B
When request comes, only controller which should process request is instantiated automatically. You can instantiate second controller manually, but I would recommend to move MethodA functionality either to base controller class
public class BaseController : ApiController
{
// ...
public IHttpActionResult MethodA(int id)
{
var foo = repository.Get(id);
if (foo == null)
return NotFound();
return Ok(foo);
}
}
public class ControllerA : BaseController
{
//...
}
public class ControllerB : BaseController
{
public IHttpActionResult MethodB(int id)
{
var result = MethodA();
//..
}
}
or move common logic to separate class (e.g. service), so you would be able to call it from both controllers.
public class ControllerA : ApiController
{
private IFooService fooService;
public ControllerA(IFooService fooService)
{
this.fooService = fooService;
}
public IHttpActionResult MethodA(int id)
{
// use fooService.Method()
}
}
public class ControllerB : ApiController
{
private IFooService fooService;
public ControllerB(IFooService fooService)
{
this.fooService = fooService;
}
public IHttpActionResult MethodB(int id)
{
// use fooService.Method()
}
}
I would consider using a common base class for the two controllers (if there is a method you want to use on both)
for example
public abstract class MyBaseController
{
public void CommonMethod()
{
// Do something here
}
}
then use them like
public class ControllerA : MyBaseController
{
public void MethodA()
{
base.CommonMethod();
// Do something else
}
}
public class ControllerB : MyBaseController
{
public void MethodB()
{
base.CommonMethod();
// Do Something else
}
}
1) You can use static class and static method inside to share it for another controllers
public static class CommonMethods
{
public static string SomeMethod(string s)
{
string RetString;
...
return (RetString);
}
}
Now you can use it in any controllers
string SomeMethodResult = CommonMethods.SomeMethod("Say Hello");
2) And another method is to create an instance of a controller class and call instances methods:
public class V1Controller : ApiController
{
public void Put(int id, [FromBody]string value)
{
HomeController hc = new HomeController();
hc.SomeMethod();
}
}
AController aController = new AController();
var getResponse = aController.YourMethod(values);
If your method returns Json then you can easily solve it with
JavaScriptSerializer().Deserialize
Related
I need to automatically add api/ prefix to every end point in my asp .net core web API. How to do that?
You can custom MvcOptionsExtensions to set route prefix globally instead of change the route attribute manually.
1.custom MvcOptionsExtensions:
public static class MvcOptionsExtensions
{
public static void UseRoutePrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
{
opts.Conventions.Add(new RoutePrefixConvention(routeAttribute));
}
public static void UseRoutePrefix(this MvcOptions opts, string
prefix)
{
opts.UseRoutePrefix(new RouteAttribute(prefix));
}
}
public class RoutePrefixConvention : IApplicationModelConvention
{
private readonly AttributeRouteModel _routePrefix;
public RoutePrefixConvention(IRouteTemplateProvider route)
{
_routePrefix = new AttributeRouteModel(route);
}
public void Apply(ApplicationModel application)
{
foreach (var selector in application.Controllers.SelectMany(c => c.Selectors))
{
if (selector.AttributeRouteModel != null)
{
selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel);
}
else
{
selector.AttributeRouteModel = _routePrefix;
}
}
}
}
2:Register in Startup.cs(version before .Net6) or in Program.cs(version beyond .Net 6):
services.AddControllers(o =>{
o.UseRoutePrefix("api");
});
Or:
builder.Services.AddControllers(o =>{
o.UseRoutePrefix("api");
});
Make your controller constructor with Route Prefix "api/"
For example lets say your controller class name is CustomerController
[Route("api/[controller]")]
public class CustomerController : ControllerBase
{
}
// This will become api/customer
[HttpGet]
public async Task<ActionResult> GetCustomers()
{
// Code to get Customers
}
// This will become api/customer/{id}
[HttpGet]
[Route("{id}")]
public async Task<ActionResult> GetCustomerById(int id)
{
// Code to get Customer by Id
}
we can simply add that in top of the controller like this
[Route("api/[controller]")]
public class TestController : ControllerBase
{
[HttpGet("version")]
public IActionResult Get()
{
return new OkObjectResult("Version One");
}
[HttpGet("Types")]
public IActionResult GetTypes()
{
return new OkObjectResult("Type One");
}
}
so that you can access like below
....api/Test/version
....api/Test/Types
Seems you can use a constant.
public static class Consts
{
public const string DefaultRoute = "api/[controller]";
}
and re-use it everywhere. If you need to change the default route everywhere - just change the constant.
[Route(Consts.DefaultRoute)]
public class TestController : ControllerBase
{
...
}
I have the generic BaseController like this:
public class BaseController<T> : Controller where T : BaseEntity
{
protected readonly IRepository _repository;
public BaseController(IRepository repository)
{
_repository = repository;
}
// POST: TController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public virtual async Task<IActionResult> Create(T item)
{
try
{
if (ModelState.IsValid)
{
await _repository.AddAsync(item);
}
return RedirectToAction(nameof(Index));
}
catch
{
return PartialView();
}
}
Do I correctly override this action in the derived controller class
public class PaysController : BaseController<Pays>
{
public PaysController(IRepository repository): base(repository) { }
// POST: Pays/Create
[HttpPost]
[ValidateAntiForgeryToken]
public override async Task<IActionResult> Create([Bind("IDPays,Code,Nom")] Pays pays)
{
return await base.Create(pays);
}
Especially, should I reuse the method attributes(like ValidateAntiForgeryToken), and will the binding Bind work in that case?
Method attributes do not need to be reused on the overriden method:
var attributes = typeof(PaysController).GetMethod("Create").GetCustomAttributes(false);
Debug.Assert(attributes.Any(x => x.GetType() == typeof(HttpPostAttribute)));
Debug.Assert(attributes.Any(x => x.GetType() == typeof(ValidateAntiForgeryTokenAttribute)));
The binding Bind will work in the overrided method. You will need to mark the base controller as abstract, otherwise ASP.NET Core does not know, which controller and endpoint to choose and throws an exception:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The
request matched multiple endpoints
We have a Asp.net MVC Project that it has over 1000 ActionResult and I need to add all of them a C# Function for check value of Session.
So What is your offer to do this?
These two following lines has some example of my Controller and ActionResult :
public partial class CRMController : Controller
{
public ActionResult OrganizationCategory()
{
//I want add a C# function here
}
}
public partial class BaseInfoController : Controller
{
public ActionResult Lead()
{
//I Want Add a C# Function here
}
}
You can use ActionFilters for this.
The base ActionFilterAttribute class has the following methods that
you can override:
OnActionExecuting – This method is called before a controller action
is executed. OnActionExecuted – This method is called after a
controller action is executed. OnResultExecuting – This method is
called before a controller action result is executed. OnResultExecuted
– This method is called after a controller action result is executed.
Here full code example !
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Log("OnActionExecuting", filterContext.RouteData);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
Log("OnActionExecuted", filterContext.RouteData);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
Log("OnResultExecuting", filterContext.RouteData);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
Log("OnResultExecuted", filterContext.RouteData);
}
private void Log(string methodName, RouteData routeData)
{
var controllerName = routeData.Values["controller"];
var actionName = routeData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
Debug.WriteLine(message, "Action Filter Log");
}
}
[LogActionFilter]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
}
Please create a action filter attribute, in that check sessions. Then create a Base Controller, then apply this attribute in that controller. Then inherit this base controller with your business controllers.
public class MySessionCheckFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
//Check Session Method()
//if(SessionNotAvaliable)
//{
// throw new businessException;
//}
base.OnActionExecuting(context);
}
}
[MySessionCheckFilterAttribute]
public class BaseController:Controller
{
}
public class YourController_One: BaseController
{
//Do anything
}
public class YourController_Two : BaseController
{
//Do anything
}
Since your function is on checking the Session, i thought it could relates to an authorization process. If so, you can try with AuthorizeAttribute
Example: Checking the Session["username"] on every Function that tagged with [AuthorizeAttribute]:
public class SessionAuthAttribute : AuthorizeAttribute
{
public SessionAuthAttribute() { }
public override void OnAuthorization(AuthorizationContext filterContext)
{
//base.OnAuthorization(filterContext);
var userID = filterContext.HttpContext.Session["username"];
if (userID == null)
{
filterContext.Result = new RedirectResult("/Home");
}
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Home",
action = "Index"
})
);
}
}
In Controller:
[SessionAuthAttribute] //Applied for whole Controller
public class HomeController : Controller
{
[SessionAuthAttribute] //Applied for 1 function
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
}
EDIT: You can create this class in folder Attribute of your MVC Project
I'm having problems routing to my BaseController for controllers where I define extra [ODataRoute]s.
GET ~/odata/Foos WORKS
GET ~/odata/Foos(1) WORKS
GET ~/odata/Foos(1)/Bars WORKS
GET ~/odata/Bars 404 Not Found
BaseController
public abstract class BaseController<T> : ODataController where T : class
{
protected IGenericRepository<T> Repository;
public BaseController(IGenericRepository<T> repository)
{
Repository = repository;
}
[EnableQuery]
public IHttpActionResult Get() // <---------- THIS IS THE PROBLEM
{
return Ok(Repository.AsQueryable());
}
[EnableQuery]
public IHttpActionResult Get(int key) // WORKS
{
var entity = Repository.GetByKey(key);
return Ok(entity);
}
}
Controllers
public class FoosController : BaseController<Foo>
{
public FoosController(IGenericRepository<Foo> repository)
: base(repository)
{
}
// Can route to base without problems
// Both base.Get() and base.Get(1) works
}
public class BarsController : BaseController<Bar>
{
public FoosController(IGenericRepository<Bar> repository)
: base(repository)
{
}
// Can't route to base.Get()
// But base.Get(1) works
// GET /Foos(1)/Bars
[EnableQuery]
[ODataRoute("Foos({key})/Bars")]
public IHttpActionResult GetBars(int key) // WORKS
{
var result = Repository.AsQueryable().Where(x => x.FooId == key);
return Ok(result);
}
}
Additionally I tried going the convention way. But that doesn't work either.
public class FoosController : BaseController<Foo>
{
public FoosController(IGenericRepository<Foo> repository)
: base(repository)
{
}
// GET /Foos(1)/Bars
[EnableQuery]
public IHttpActionResult GetBars(int key) // WORKS
{
var result = Repository.AsQueryable().Bars;
return Ok(result);
}
}
I have a custom ActionFilterAttribute. For the sake of this question let's assume it's as follows:
public class CustomActionFilterAttribute : ActionFilterAttribute {
public bool success { get; private set };
public override void OnActionExecuting(HttpActionContext actionContext) {
//Do something and set success
success = DoSomething(actionContext);
}
}
My controller is then decorated with CustomActionFilter. What I am looking for is a way (in my controller method) to do something like:
[CustomActionFilter]
public class MyController : ApiController {
public ActionResult MyAction() {
//How do I get the 'success' from my attribute?
}
}
If there is a more accepted way of doing this please let me know.
I discovered I could do the following to satisfy my problem:
[CustomActionFilter]
public class MyController : ApiController {
public ActionResult MyAction() {
var myAttribute = ControllerContext
.ControllerDescriptor
.GetCustomAttributes<CustomActionFilter>()
.Single();
var success = myAttribute.success;
}
}