return renderview instead of return view - c#

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.

Related

What happening behind scene when we want to render view?

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.

Work with Controller and Action without sending a redirect?

I have some server side code that runs some rules and than will redirect to differing controllers and actions depending on the outcome of the rules.
Whats the best way to represent a Controller and Action combo without doing the RedirectToAction("Action","Controller"); because I dont actually want to issue the redirect right after the method executes.
so i want to do something like
public SomeObject ApplyRules(){
if(somecondition){
return(Action1,Controller1);
else if(someotherCondition){
return(Action2,Controller2);
}
}
I can create a class that has two string properties (Controller, and Action) but I have to think there is some built in class that I should be using to represent this.
You can use RedirectToRouteResult type and pass it around. You don't have to create new objects or tuples.
[NonAction]
private RedirectToRouteResult ApplyRules(){
if(condition1){
return RedirectToAction("Action1");
}
else if(condition2){
return RedirectToAction("Action2");
}
else return RedirectToAction("Action3")
}
public ActionResult MyAction()
{
RedirectToRouteResult result = ApplyRules();
// As long as you don't return your "result" from THIS METHOD
// redirect won't happen:
// return result;
return View();
}
As long as you don't return RedirectResult from your ACTION method, you can use it as return parameter of your ApplyRules() or any other method.
If your ApplyRules() method is outside of Controller, you cannot use RedirectToAction helper. In that case you can generate RedirectToRouteResult like this:
var routeValues = new System.Web.Routing.RouteValueDictionary();
routeValues.Add("controller", "Account");
routeValues.Add("action", "Register");
var result = new RedirectToRouteResult(routeValues);
I don't normally use tuples, but this could be a situation where it makes sense:
public Tuple<string,string> ApplyRules(){
if(somecondition)
{
return(new Tuple<string, string>("Action1","Controller1"));
}
else if(someotherCondition)
{
return(return(new Tuple<string, string>("Action2","Controller2")););
}
}
Learn more about tuples at this msdn post.
You would of course do your redirect, something like this:
public void DoMyRedirect(Tuple<string,string> route)
{
return RedirectToAction(route.Key1, route.Key2);
}

How to withdraw code from an action method into helper in Asp.Net MVC 3?

I'm writing my app using Asp.Net MVC 3. In my controller I have two action methods with the very same code apart from one line. Here it is:
[HttpPost]
public ActionResult EditPost(Post post)
{
if (ModelState.IsValid)
{
_postsRepository.UpdatePost(post);
return RedirectToAction("NewsFeed");
}
return View("EditPost", post);
}
[HttpPost]
public ActionResult AddPost(Post post)
{
if (ModelState.IsValid)
{
_postsRepository.UpdatePost(post);
return RedirectToAction("NewsFeed");
}
return View("AddPost", post); // the return view is different
}
So, I want to withdraw all this code into helper method.
What I've already tried:
1) I tried to put all the code into helper method and pass as parameters ModelState.IsValid and View name. And then in AddPost and EditPost I call this helper method instead of code listed above. Here is the new code:
[HttpPost] // also tried without this attribute
public ActionResult HelperPost(Post post, string viewName, bool modelState)
{
if (modelState)
{
_postsRepository.UpdatePost(post);
return RedirectToAction("NewsFeed");
}
return View(viewName, post);
}
[HttpPost] // also tried without this attribute
public void AddPost(Post post)
{
HelperPost(post, "AddPost", ModelState.IsValid);
}
The EditPost code is almost the same. The view name is "EditPost".
When I run the app and AddPost method executes the validation works and the new post is created but this line never executes:
return RedirectToAction("NewsFeed");
So I'm redirected to "AddPost" view again and again.
2) Also tried to redirect to HelperPost method instead of calling it withing AddPost and EditPost. The result is still the same: seems like RedirectToAction("NewsFeed") doesn't execute. (Here I neglected the validation just to simplify the example, cause I would have to create new model with properties: Post post, string viewName, bool modelState). The code:
[HttpPost] // tried without attribute
public void AddPost(Post post)
{
return RedirectToAction("HelperPost", post);
}
[HttpPost] // tried without attribute
public RedirectToRouteResult HelperUpdatePost(Post post)
{
_postsRepository.UpdatePost(post);
return RedirectToAction("NewsFeed");
}
So, How could I refactor my code so my action methods (EditPost and AddPost) would not contain the same chunk of code?
p.s. I need different views for AddPost and EditPost methods cause the "back to content" links in them are different. So, I can't just redirect to the EditPost view from AddPost method.
Thanks for help in advance!
Just put your "back to content" link in the model, then use the same view for both, then you can use the same HttpPost method. Saves having to duplicate everything.
I would solve it like this:
I would withdraw the method implementation into separate private
method. This method will be invoked by each of the public action
methods. Since the View name differs for both methods I would pass
the view name as parameter to the private method.
The private method doesn't need the HttpPostAttribute!
Don't forget to declare Add and Edit action methods as returning
ActionResult! As parameter they will expect only Post, the view name has to be hard-coded into the action methodsiteslf ;-)
I hope this helps.

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.

Overloading Controller methods with custom JSON(POST) binding in MVC3

I reached a road bump while trying to use some of the cool new feature of MVC 3.
Is it possible to overload controllers using custom JSON binding using MVC3 ?
It doesnt look like it works automatically as of now....
What's the neatest way to do this ?
For example
If I want to implement the following endpoint
[HttpPost]
public ActionResult GetPet(Cat catObject)
{
return Json(catObject.purr());
}
overloaded with this endpoint
[HttpPost]
public ActionResult GetPet(Dog dogObject)
{
return Json(dog.bark());
}
Is there any way i can do this without using thirdparty libraries Or System.Web.Script.Serialization.JavaScriptSerializer
Also Is there any particular reason this is not implemented in mvc3 yet?
Overloading Json objects on controllers seems a distant possibility now rather than a present reality.
This is the closest I could get to overloading the action
[HttpPost]
public ActionResult GetPet()
{
Cat catObj;
Dog dogObg;
if (TryUpdateModel(catObj))
return Json(catObj.purr());
else
{
ModelState.Clear();
if (TryUpdateModel(dogObg))
return Json(dogObj.bark());
else
{
ModelState.Clear();
ModelState.AddModelError("InvalidInput", "The given input does not match with any of the accepted JSON types");
return new HttpBadRequestResult(ModelState);
}
}
}

Categories