Return view not picking up new view - asp.net

I am trying to change the view that on of my controllers points to however this is not picking up the amendment. The following is the code I am trying to use;
// GET: UserDemographics/Create
public ActionResult Create()
{
return View("Manage");
}
And my views folders look like below:
My understanding is that View tries to check for the same name as the method but I may be wrong. Any help would be appreciated.

Nothing wrong in your code. This should work perfectly
Your URL should be like this,
localhost:[Port Number]/userdemographics/Create
If you already hosted your project in a real domain, then you can replace localhost:[Port Number] with your domain name. For example,
www.example.com/userdemographics/Create

The view name specified within the View() method does not alter the path in the URL when making a request, it simply changes the name of the view that is rendered as a result of the request.
If you want the path to your action to be /UserDemographics/Manage, you would need to change the name of your Action method to Manage.
public class UserDemographics : Controller
{
// Requested by /UserDemographics/Manage in the browser
public ActionResult Manage()
{
// You don't HAVE to specify the view name here, Manage.cshtml will be rendered based on the convention.
// However as mentioned this is best practice to specify the name.
return View("Manage");
}
}
This makes it so that there is no longer a need to specify the View name as it will be automatically selected from the Views folder by convention for that controller.

Related

asp.net Entity Framework is it possible to change client values by post method

I'm working on a project using asp.net MVC with Entity Framework.
I was requested to combine the Create page and Edit page together.By another word, if no record , create it, otherwise, edit it. But it brings a problem:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
if (ModelState.IsValid)
{
if(movie.ID ==0)
{
db.Movies.Add(movie);
}
else
{
db.Entry(movie).State = EntityState.Modified;
}
db.SaveChanges();
}
return View(movie);
}
From above code, you can see that I check the property "id" in DBcontext to know whether it's a new record or existed one.
But during test, I found that If I create a record without close the webpage,and change some values, press the "save" button in browser again, a new record will be created instead of modify the record just created.
I have traced the whole workflow and found that:
When I click the Save button first time to create the record, the "id" of movie object does changed after Savechanges function.
When the browser reload the page after creation, the id property of Model in the webpage is really changed to non-zero.
But finally the display result of ID on webpage is still zero~!!! So at the second time, the controller get the value from webpage's form element with 0.
4.No matter I use hiddenfor , hidden, editFor in webpage, the result is the same.
5.Since the validation error message shows on webpage is also changed via post method, I think there maybe some internal settings of EF to prevent value change. But even if I deleted AntiForgery attribute from both controller and webpage side, the result is also the same...
Is there anyone who can help?

Attribute routing default url

I have the following method in my controller, using C# MVC with Attribute roouting:
[Route("")]
[Route("/something-else")]
public IActionResult Index(){
}
Im using two different routes to access this functionallity, since i want customers with bookmarks to the previous implementation to work.
The problem is that i cant specify which of these Routes will be the default one when i issue the action like this:
<a asp-controller="FOO" asp-action="Index">
Everythiing works as expected, both URLs work, but i cant specify which of these routes will be used when navigated to by the action, via the action above.
I would like that the first route be used everytime i navigate to this action, except when someone explicitly writes the old url into the browser.
Are there any default attributes to the [Route("")] tag?
The RouteAttribute class has an Order property. From the docs:
Gets the route order. The order determines the order of route execution. Routes with a lower order value are tried first.
For example:
[Route("/something-else", Order = 1)]
[Route("", Order = 2)]
public IActionResult Index(){
}
As an aside, I would strongly discourage you from serving the same page with multiple URLs. Google's indexing will give you worse ranking because of it. Instead, consider returning a redirect to the new URL instead.

Load different view based on url parameter with out changing controller action method in asp mvc

I was wondering if below hack is possible or not.
Tried multiple ways but it will require some conditional statements in action method.
I am looking for solution based on routing most probably but not sure how it is possible.
Suppose I have single Acton Method Index()
public ActionResult Index()
{
return View();
}
above method is under home controller.
In addition inside Views > Home folder there are two view files...
Index.cshtml
Index_New.cshtml.
I believe that it is possible to load different Views using id passed in URL parameter but that will require change in above action method and i don't want that.
Can we do something without changing action method so that
http://example.com/Home/Index should load Index.cshtml
and
http://example.com/Home/New/Index should load Index_New.cshtml?
Create a new action method. Update your route registrations so that the request yourSite/Home/News/Index will be handled by this new aciton method.
The below code uses attribute routing to specify the route pattern for the new action method. You can pass the view name to the view method if you want to return something different than the convention (the action name)
[Route("Home/News/Index")]
public ActionResult NewsIndex()
{
return View("Index_New");
}

How to bind form collection back to custom model object that uses 2 custom objects in asp.net mvc?

What I'm trying to do is rather basic, but I might have my facts mixed up. I have a details page that has a custom class as it's Model. The custom class uses 2 custom objects with yet another custom object a property of one of the 2. The details page outputs a fair amount of information, but allows the user to post a comment. When the user clicks the post button, the page gets posted to a Details action that looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Details(VideoDetailModel vidAndComment) { ....}
The only fields on the form that is posted are CommentText and VideoId. Here is what the VideoDetailModel looks like.
public class VideoDetailModel
{
public VideoDetailModel()
{
Video = new VideoDTO();
Comment = new CommentDTO();
}
public VideoDetailModel(VideoDTO vid)
{
Video = vid;
Comment = new CommentDTO();
}
public VideoDTO Video { get; set; }
public CommentDTO Comment { get; set; }
}
VideoDTO has a few properties, but the ones I need are VideoId. CommentDTO's pertinent properties include CommentText (which is posting correctly) and a UserDTO object that contains a userId property. Everything other than the CommentText value is not being posted. I also have the following line on the ascx page, but the model value never gets posted to the controller.
Html.Hidden("Model.Video.VideoId", Model.Video.VideoId);
I'm really not sure what I'm missing here. I suppose if I added more form fields for the properties I need, they would get posted, but I only need 1 form entry field for the CommentText. If I could get the same Model objects value that were sent to the page to post with the page, that would help.
I'll be happy to make any clarifications needed here. I'm just at loss as to what's going on.
UPDATE
Okay, it looks like the solution is rather simple. I think using the RenderPartial in the middle of a form is problematic somehow to how the form gets written in html. I can't really put my finger on why things went bonkers, but if I do my RenderPartials before my form and then begin my form with the text entry field and the hidden VideoId, the default ModelBinder works just fine. I was beginning the form, writing the hidden VideoId, rendering several partial views, create my CommentText field, and then closed the form out. The CommentText field would get bound just fine. The hidden VideoId would not. Maybe I missed a rule somewhere about using RenderPartial.
For completeness, the partial view I was rendering took a Comment object and just wrote out it's CommentText data. Several of these objects would exist for a single Video object. All of this data was in a custom type and passed into the View (the main view) as it's Model. This partial view did not have a form and did not have any data entry fields.
I'd need to see more of your view page code to really give a thorough answer here but for the one snippet you posted:
Html.Hidden("Model.Video.VideoId", Model.Video.VideoId);
Should really be:
Html.Hidden("Video.VideoId", Model.Video.VideoId);
or
Html.Hidden("vidAndComment.Video.VideoId", Model.Video.VideoId);
Either way will work but I tend to prefer the first if your controller action only takes a single parameter. The default model binder will be (in your example) looking for a method parameter named "Model" or failing that will look for a property "Model" on your VideoDetailsModel class. Since neither of those exist, it can't bind "Model.Video.VideoId" to anything.
Is there any Model Binding Security implemented in your mvc site? To explain what I mean, take a look at this page and read the section near the end titled "Model Binding Security". Note that this can be within your code OR in your global.asax file.

Most Correct way to redirect page with Model-View-Presenter Pattern

What is the best way to call a Response.Redirect in the Model-View-Presenter pattern while adhering to correct tier separation?
One way I handled this is for the presenter to raise an event (like Succeeded or something) that the view would subscribe to. When the presenter finished it's processing, it would raise the event, which would get handled by the View. In that handler, the view would redirect to the next page.
This way, the presenter doesn't need to know anything about pages or URLs or anything. It just knows when it has completed its task and lets the view know by raising an event. You can raise different events if the presenter succeeded or failed, in case you need to redirect to different places.
I do not know whether it is the most correct way, conceptually.
But what I did in my last MVP-applications, is create a wrapper around HttpContext.Current which I called HttpRedirector.
I also created a dummy redirector for testing purposes. Both keep track of the last redirected url, so that I can check in my unit tests that the redirect actually happened when I call a method on my controller/presenter. With an IOC-container I am able to switch the implementation of IRedirector based on the environment (production/test).
The way we do it works nicely once some ground work is laid. I'm sure there are several ways to skin a cat though. (Who skins cats anyway. Cats are cute and cuddly!)
First, this will only work on the ASP.Net compiled Web Projects, not Websites.
Each page should inherit from a custom abstract base class which looks something like this:
public abstract class PageBase : Page
{
private static string _baseUrl = "/";
public static string BaseUrl
{
get { return _baseUrl; }
set { _baseUrl = value; }
}
protected static string BuildUrl(string basePath)
{
if( !string.IsNullOrEmpty(basePath) && basePath.StartsWith("~/"))
{
basePath = basePath.replace("~/", BaseUrl);
}
return basePath;
}
protected static string LoadView(string path)
{
Response.Redirect(path);
}
}
Each page also implements a page-specific interface. Each page-specific interface also inherits from a base interface:
public interface IPageBase()
{
void LoadView(string path);
}
Then it's a matter of each page defining it's own version of BaseUrl. You might want to account for querystrings/path encryption/etc.
Finally, any of your presenters (which should be referencing the page-specific interfaces) can grab the static BuildUrl() on a desired page to view and then call LoadView() with the returned path.
It depends how generic your presenters are. If your presenters are totally UI agnostic (can be reused between WinForms and WebForms) then you'll have to abstract the redirection operation. In WebForms, the redirection operation would be implemented in the view by a Response.Redirect. In WinForms, (I disclaim lots of experience with WinForms) my guess is that it would be implemented by SomeForm.Show.
One simple, off-the-top-of-my-head option would be to include in the view's interface a ShowViewX() method. You can have one for each form the view could logically redirect to. Alternatively, the view can implement an interface method like Show(ConnectedViews) where ConnectedViews is an enum that includes a value for each of the views that can be "redirected" to from a particular view. This enum would live at the presenter level.
The above approaches are specific to view-presenter pairs. You could instead implement it as a system-wide thing. The logic would be similar to above, implemented in the base view and presenter. There would be a ShowView__() for each form, or a Show(Views) method where Views is an enum of all forms.
It's a toss-up between encapsulation and DRY-ness.

Resources