What happening behind scene when we want to render view? - c#

ActionResult is the base class for the various return types to View in MVC. So your action must return an ActionResult or a class derived from it in order to work.
so we can use
public ContentResult Index()
{
return Content("Hello world");
}
or for example
public ViewResult Index()
{
return View();
}
or ActionResult
public ActionResult Index()
{
if (ViewBag.Hello = "World")
return Json("");
return PartialView();
}
BUT also is possible use string !!!
public string Index()
{
return "Hello World";
}
WHY is than not possible return integer to view? (Or maybe it is?)
public int Index()
{
return 4;
}
and not possible return some entity to view (Or maybe it is?)
public User Index()
{
return new User();
}
My question is : What happening behind scene when we want to render view?

I agree that this is quite a broad question, but I wanted address and answer a few of the points you raised in your question.
You can return an int, string or object from your action method and it will simply return the object's string representation as the result.
Therefore you don't have to return an object of type ActionResult in order for it to work, but the ActionResult enables useful functionality through it's various implementations so that ASP.NET MVC Framework can handle different scenarios straight out of the box.
Such as returning views and handling the ViewModel you want to pass to your view:
return View(); // Default view without view model
return View(viewModelObject); // Default view with a view model
Returning views based on your routing information:
return View("viewName", viewModelObject);
Performing redirects to another page, using your routing information:
return RedirectToAction(actionName, controllerName);
Returning a page with specific status codes:
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
Returning JSON instead of a view:
return JsonResult(myObject);
All of the above examples do different things, return different types of results and handle your objects for you so that you don't have to code the behaviour yourself - they're ready for you to use.
Another handy thing is that you can create your own implementations of ActionResult to create your own behaviour, so it's very flexible in that regard.
I agree with #Daniel J.G. that you should do some more reading on how ASP.NET MVC hangs together and it will become a lot more clear to you.

Related

What is the difference between rendering a view and returning a view in ASP.NET MVC? Also, what is the difference between ActionResult and ViewResult? [duplicate]

This question already has answers here:
ViewResult V/S ActionResult
(3 answers)
Closed last month.
I am new to ASP.NET MVC. Could you explain what is the difference between ActionResult and ViewResult? Does it matter if use ActionResult as the return type for my actions instead of view.
And what do you mean by rendering a view and returning a view?
These are two actions. Would it matter if i change the Index() type from ViewResult to ActionResult?
public ViewResult Index()
{
var customers = GetCustomers();
return View(customers);
}
public ActionResult Details(int id)
{
var customer = GetCustomers().SingleOrDefault(c => c.Id == id);
if (customer == null)
return HttpNotFound();
return View(customer);
}
A ViewResult is a type of ActionResult. The View helper method in this line return View() is actually just shorthand for return ViewResult(). So, you are returning a ViewResult and because that is a type of ActionResult, you can set the return type of your method (for example Details) to ActionResult.
Here is more information about the ViewResult class https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.viewresult?view=aspnetcore-7.0
For the other part of your question, rendering vs returning a view. As far as I know, a view is returned in the action response method (as you have shown). A view is only rendered when you are using a partial view and want to render the partial view within another view. In this case, the partial view is rendered in the view file itself. So you ultimately still only need to return the view in the action response method, as the partial view will be rendered within it.
For more information on rendering partial views, look here: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-7.0
Here is the link for the same question about ActionResult and ViewResult Difference Between ViewResult() and ActionResult()
TLDR: ActionResult is an abstract class, and ViewResult derives from it. In most cases you should use ActionResult as a method return type because it's more convenient and flexible (you can return any class that derives from AcionResult). But if you will use ViewResult as the return type for a method you have to return the ViewResult or any different class that derives from it

ASP.NET MVC Return Overloaded Get Action

I am using MVC 4, and I have the following:
[HttpGet]
public ActionResult SomeForm(modelType model = null)
{
if(model != null)
return View(model);
return View(getModelFromSomewhere());
}
[HttpPost]
public ActionResult SomeForm(modelType model)
{
if(isValid())
doSomething();
else
return SomeForm(model) // Line in Question
}
However, obviously, I am getting an ambiguous method error on "Line in Question". I'm wondering if anyone has an elegant solution to be able to specify to return specifically the [Get] method of the same name?
Thank you!
You can't have methods with the same signature as you've pointed out already. In C# it also means you can't distinguish functions by just return type - so you must use different names if parameters are same (again default values are ignored when matching of signatures).
If you want separate GET and POST handler - use different names of methods and ActionNameAttribute to name the action:
[HttpGet]
[AciontName("SomeForm")]
public ActionResult SomeFormGet(modelType model = null) ...
[HttpPost]
[AciontName("SomeForm")]
public ActionResult SomeFormPost(modelType model) ...
make it compile...
[HttpPost]
public ActionResult SomeForm(modelType model, FormCollection fc)
{
if(isValid())
doSomething();
else
return SomeForm(model) // Line in Question
}
If you are using http get method you are waiting that browser will send you serialized model as a string query. For example, you are waiting url like
http://example.com?name=Andrew&type=Worker&field1=param1&field2=param2&....
It is common practice to use only id in your get method, so you can do it like this:
[HttpGet]
public ActionResult SomeForm(int id)
{
var model = FindModelById(id);
if(model != null)
return View(model);
return View(getModelFromSomewhere());
}
If you are looking for an elegant solution, it will be more elegant in architecture

return renderview instead of return view

I am used to:
public ActionResult CreateSomething()
{
return View("ViewName", new CreateSomeDto());
}
I just encountered this in some legacy code:
public ActionResult CreateSomething()
{
return RenderView("ViewName", new CreateSomeDto());
}
Could someone please explain the difference?
RenderView() is an antiquated method from MVC 1.0
The ViewEngine was less sophisticated. Controller methods did not return ActionResults. In fact, they returned void. A RenderView call does not return a string, but rather "renders" or writeln's the view into place.
It's functionality is very similar to the way Html.RenderPartial()'s are rendered into a View.

Determine which ASP.NET MVC View to return when not using return View(model) but return View("viewName", model)

I have my mvc site working well with mobile and non-mobile browsers; the issue I'm having is this. I have a couple Actions that (for logging reasons) I don't want to do a return RedirectToAction(...); on so instead I had been using return View("OtherView", model); this worked until I tried it on mobile, and it doesn't find OtherView.Mobile.cshtml. Is there a way to make this work?
Thise are the views
Views/Account/Create.cshtml
Views/Account/Create.Mobile.cshtml
Views/Account/CreateSuccess.cshtml
Views/Account/CreateSuccess.Mobile.cshtml
This is the Action
public ActionResult Create(FormCollection form)
{
TryUpdateModel(model);
if(!ModelState.IsValid) { return View(); } // this works correctly
var model = new Account();
var results = database.CreateAccount(model);
if(results) return View("CreateSuccess", model); // trying to make this dynamic
return View(model); // this works correctly
}
Normally I would just do return RedirectToAction(...); to the account detail page, but this will generate an additional log entry (for this user being read) as well as the detail page does not have access to the password. Since ActionResult Create had the password originally, it can show it to the user for confirmation, before its never seen again.
To be clear, I do not want to do if (Request.Browser.IsMobileDevice) mobile else full because I may end up adding another set of mobile views for for iPad or whatever:
Views/Account/Create.cshtml
Views/Account/Create.Mobile.cshtml
Views/Account/Create.iPad.cshtml
Views/Account/CreateSuccess.cshtml
Views/Account/CreateSuccess.Mobile.cshtml
Views/Account/CreateSuccess.iPad.cshtml
I would just set a session variable on their first usage that would be a "delivery type" identifying all supported views.
public enum DeliveryType
{
Normal,
Mobile,
Ipad,
MSTablet,
AndroidTablet,
Whatever
}
Then you could have a property or extension method somewhere
public DeliveryType UserDeliveryType
{
get
{
return (DeliveryType)Session["DeliveryType"];
}
set
{
Session["UserDeliveryType"] = value;
}
}
You could even put in a different method to delivery the View "add on":
public string ViewAddOn(string viewName)
{
return (UserDeliveryType != DeliveryType.Normal) ?
string.Format("{0}.{1}", viewName, UserDeliveryType.ToString()) :
viewName;
}
Then your ultimate call could be:
if (results) return View(ViewAddOn("CreateSuccess"), model);
Then you'd just have to make sure that for every delivery type you have a corresponding view. It may be prudent to build some kind of checker to verify you have a matching view and if not return the standard view.
you can create a pseudo-view that has a Partial with a ViewData variable. #Html.Partial will find the correct view.
something like this:
CustomView.cshtml:
if (ViewData.ContainsKey("PartialViewName")) {
#Html.Partial(ViewData[PartialViewName]);
}
Controller.cs:
public ActionResult Create(FormCollection form)
{
TryUpdateModel(model);
ViewData[PartialViewName] = "CreateSuccess";
if(!ModelState.IsValid) { return View(); } // this works correctly
var model = new Account();
var results = database.CreateAccount(model);
if(results) return View("CustomView", model); // trying to make this dynamic
return View(model); // this works correctly
}
you can have now CreateSuccess.cshtml and CreateSuccess.Mobile.cshtml.
note: you only need ONE CustomeView.cshtml in your all your application.
note2: you can always pass parameters in another fashion like viewbag, or whatever technique makes you feel more confortable :D
It's more a bit of hack than a solution. Let us know if you came up with something prettier.

Is it possible to make a non ActionResult Method to return an ActionResult... Or best/neatest workaround?

I have an object from a database that is used in a lot of places in my application.
The actual precise object is a bit complicated to build, and, especially during development, I have changed it several times. For this reason, I extracted the method out of the Controller and built a method that has a return type of the object.
However, it was possible that this object did not exist, and if it did not, my code would create it and return it.
For example:
public ActionResult Index()
{
var model = GetTheObject();
return View(model);
}
public MyComplicatedObject GetTheObject()
{
MyComplicatedObject passback = ...database query....
if(passback==null)
create the object here....
return passback;
}
However, I no longer want to create a default object. If it does not exist, I want the user to be sent to a view to create a new one.
I don't know if it is because I am coding at almost 4AM, or if I am just not that good, but, a neat way of doing this is escaping me.
I know the following won't work, but ideally this is what I want:
public MyComplicatedObject GetTheObject()
{
MyComplicatedObject passback = ...database query....
if(passback==null)
return View("CreateObject");
return passback;
}
Obviously though, this will not work.
The best solution I can think of is to basically return either null or an exception, then have if(passback==null)&return View("CreateObject"); (in case of a null) on the ActionResult.
However, as I want to repeat this in a few places, it makes more sense to be able to just have GetTheObject() in one line/call from the ActionResult and nothing else.
Is there any way to achieve this?
I have a similar scenario where I want to return a "NotFound" view in case that my repository returns a null object. I implemented a ViewForModel helper method to avoid repeating myself:
public ActionResult Details(int id)
{
var model = _repository.Retrieve(id);
return ViewForModel("Details", model);
}
public ActionResult Edit(int id)
{
var model = _repository.Retrieve(id);
return ViewForModel("Edit", model);
}
private ActionResult ViewForModel(string viewName, object model)
{
return model == null
? View("NotFound")
: View(viewName);
}
Just return null from your method, and have your action method return the create view when it gets a null.

Categories