I would like to know, if it is possible for each subsequent request, to not have the default constructor in the controller invoked?
Here's the fake scenario:
I have a controller (HomeController) with 3 Action methods. Now, each method uses a property from a Customer type. I don't want this Customer Type to always be instantiated for each action method.
Sample Code:
public class HomeController : SampleController
{
public HomeController(System systemInstance)
{
base.System = systemInstance;
}
public ActionResult Index()
{
//Do something with the CustomerType
base.ValidationResult = ValidationEngine.Validate(base.Customer.Address)
return View();
}
public ActionResult Index()
{
//Do something with the CustomerType
base.ValidationResult = ValidationEngine.Validate(base.Customer.ShoppingCart)
return View();
}
}
What I'm trying to achieve it that upon the first Invocation, I instantiate the base.System Property and then for each subsequent action method, I can just reference the instantiated type.
I dont want to store this type in the Session, or in the Cache.
Hope this makes sense :)
Thank u
Related
I have the following code
public class BooksController : Controller
{
[Route("/Books/{id?}")]
public IActionResult Index(string id)
{
return View(id);
}
}
My problem is that when I try to enter the parameter it is (as it seems) considered as controller's action so I keep getting this exception.
I need somebody to explain what am I doing wrong.
If you want to pass some parameter to a view as a string you can make this like below:
public class BooksController : Controller
{
[Route("/Books/{id?}")]
public IActionResult Index(string id)
{
if (string.IsNullOrEmpty(id))
id = "default_value";
return View((object)id);
}
}
If the string type is passing to the View() call without casting to object it will be interpreted as a view name.
And the view model data should be declared as
#model string;
<h2>#Model</h2>
Try changing the route as given below -
[Route("Books", Name = "id")]
I am trying to handle a returnUrl string after login request such that:
if (returnUrl is pointing to a ViewResult)
proceed to the requested destination
else
Redirect to home
How do I determine if the url is pointing to a controller method with a return type of ViewResult?
How do I determine if the url is pointing to a controller method with a return type of ViewResult?
First, this is not a good idea. If a result of a method is ActionResult you can not ever 100% know if the result is a ViewResult, because someone could change it.
If you are really determined to do this, then every return value on every controller would have to be ViewResult. Then what you can do is create a custom AuthorizationAttribute which could then determine if the user is logged in, if the ReturnUrl is populated (or some other flag) and then using reflection (which is not great for performance, but it's only on sign-in so thats mostly ok) to determine the method's return type.
I don't see why "every return value on every controller would have to be ViewResult."
Because if you don't do this, you cannot guarantee a method with a return type of ActionResult is a ViewResult.
DotNetFiddle Example
using System;
public class Program
{
public static void Main()
{
var result = typeof(TestController).GetMethod("MyMethod").ReturnType;
Console.WriteLine("TestController:MyMethod returns {0}", result.Name);
}
public class TestController
{
public ActionResult MyMethod()
{
return new ViewResult();
}
}
// mocking System.Web.Mvc
public abstract class ActionResult { }
public class ViewResult : ActionResult { }
public class JsonResult : ActionResult { }
}
Result
TestController:MyMethod returns ActionResult
Someone changes new ViewResult() to Json(myModel) you can't detect the change through reflection.
In one of the controllers, every view has a fixed preprocessing. Is there a better way of doing this, instead of the below code; such that SomeFunctionAsync works without writing that line before return View() for all functions with return View() in this controller? I also have some ajax post functions.
public async Task<ActionResult> View1()
{
await SomeFunctionAsync();
return View();
}
public async Task<ActionResult> View2()
{
await SomeFunctionAsync();
return View();
}
In other words, at the end I want to be able to write the following with having the same effect
public async Task<ActionResult> View1()
{
return View();
}
public async Task<ActionResult> View2()
{
return View();
}
If Action Filter as suggested by Varun doesnt suits you, you can try another way.
Create a parent View of all the view. In the action method for your parent view. Call this Method SomeFunctionAsync(). Thus, parent view will be called for all of yours views and the required method will be executed
You can create a base class for your controller, and have have each view in your code call a generic method. I use GetView as a method name (or you could override the existing ones).
Like so:
public class MyControllerBase : Controller {
public Task<ActionResult> GetView() {
yourCommonMethod();
return View();
}
public Task<ActionResult> GetView(string viewName) {
yourCommonMethod();
return View(viewName);
}
public Task<ActionResult> GetView(object model) {
yourCommonMethod();
return View(model);
}
public Task<ActionResult> GetView(string viewName, object model) {
yourCommonMethod();
return View(viewName, model);
}
}
Then in your controller, inherit from that:
public class MyController : MyControllerBase {
public async Task<ActionResult> View1()
{
return GetView();
}
}
If the common method is the same for all controllers and has no controller-specific dependencies, it could be that simple. However, you may want to look at using generics as well:
public class MyControllerBase<T> : Controller {
// base class stuff here based on type T's interface
}
public class MyController : MyControllerBase<MyController> {
// regular class here, sending MyController to the base
}
These are pretty much building blocks of OOP. You may do well to get a book that covers the basics of OOP and work through this type of stuff.
There are tow ways :
Use a single Action with different views like return View("View1") or retrun View("View2"), you can make if else conditions there so you will call your function at a single place.
If you want to go with your current procedure(not recommended) then you have to use Action Filter attribute and decorate it on Controller level then every action would execute your logic before execution of your Action
I've written a base class and some classes which derive from it.
I want to use these classes in one ActionResult, but if I'm trying to cast PSBase to PS1 I'm getting a System.InvalidCastException that type PSBase can not be converted to PS1.
Classes:
public class PSBase
{
public int stationId { get; set; }
public string name { get; set; }
}
public class PS1 : PSBase
{
public string reference { get; set; }
}
public class PS2 : PSBase
{
}
ActionResult:
[HttpPost]
public ActionResult ProductionStep(PSBase ps)
{
if (ModelState.IsValid)
{
var product = db.Product.FirstOrDefault(.........);
switch (ps.stationId )
{
case 1:
{
product.Reference = ((PS1)ps).reference;
db.SaveChanges();
break;
}
}
}
return View();
}
As I don't want to have for each class a own ActionResult (repeating much of the same code many times) I wanted put all this to one ActionResult. Any Ideas how I could implement this?
What you are trying to do will never work without custom ModelBinder (and even then it will be a huge mess I'd not recommend to implement), sorry.
Only when you are passing a model from Controller to View it remembers what type it was originally (including inheritance, etc.) because at that point you are still on the server side of the page and you are merely passing an object.
Once you enter a view and submit a form all that does it creates some POST request with body containing list of values based on input names.
In your case if you have a form based on PS1 and used all the fields as inputs, you would get something like:
POST:
stationId = some value
name = some value
reference = some value
(there is no mention of the original type, controller, method, etc.)
Now, what MVC does is that it checks what argument you are using in the header of the method (in your case ProductionStep(PSBase ps)).
Based on the argument it calls a model binder. What the default model binder does is that it creates new instance of that class (in your case PSBase) and goes via reflection through all the properties of that class and tries to get them from the POST body.
If there are some extra values in the POST body those are forgotten.
Unless you write a custom model binder for this default MVC implementation can't help you there.
I'd recommend creating two separate methods, one of each accepting different implementation of PSBase.
If you want to read more on Model Binders check this out http://msdn.microsoft.com/en-us/magazine/hh781022.aspx
EDIT:
By creating two separate methods I mean something like this:
[HttpPost]
public ActionResult ProductionStepA(PS1 ps)
{
if (ModelState.IsValid)
{
}
return View();
}
[HttpPost]
public ActionResult ProductionStepB(PS2 ps)
{
if (ModelState.IsValid)
{
}
return View();
}
then you have to distinguish between them in the view via different form action.
Today I found it hard to discover the difference between two MVC action methods.
My arearegistration:
public override void RegisterArea(AreaRegistrationContext context)
{
// My test route.
context.MapRoute(
"testRoute",
"Test/{action}",
new { controller = "Test", action = "Index" }
);
}
And the two methods, that differ from both the used http-method and the parameter.
[HttpPost]
public ActionResult Test(TestModel model)
{
return View("Confirm", model);
}
[HttpGet]
public ActionResult Test(string title)
{
Response.Write(title);
Response.End();
return null;
}
Unregarded the http method, it will always end up rendering the second Test() method. Even when no title parameter is supplied (normally by querystring /Test/Test/?title=test). Probably because string is a reference type and can be null.
But how to overcome this problem? How to make a difference between these methods?
Thanks in advance.
I follow this signature, basically always use the 'GET' method signature with the model as last parameter.
[HttpPost]
public ActionResult Test(string title, TestModel model)
By the way, I've never seen the behavior you've mentioned. So I doubt whether this is a MVC problem rather than something in your configuration. [HttpGet] methods never fire on a POST method. Is the method really post (check the Request property of your ControllerContext).