Its about asp.net application that uses MVC 2.0 artcitecture - c#

Currently i am working on asp.net MVC-2 applications. i met with a problem that how to get signup form data into controller class. There is a solution that we can use FormCollection object but how to get individual field values.
Can anyone please help?

The simplest way to handle posted values is with the FormCollection object you mentioned. You can access it like an array:
public ActionResult YourAction(FormCollection form)
{
// assuming a form element posted with the name, "user"
var user = FormCollection["user"];
return View();
}
The best way to handle posted values is by using a strongly typed view model. The view model would contain properties of your form. The MVC framework will automagically bind your form elements to this object, if possible.
So, your view model class might look like:
public class UserFormViewModel
{
public string Username { get; set; }
public int Age { get; set; }
}
If your HTML form contained two inputs with their name attributes set to Username and Age, then your controller action could be modified to use the strongly types view model just described:
public ActionResult UserForm(UserFormViewModel vm)
{
string username = vm.Username;
int age = vm.Age;
// persist to database, etc
return View();
}

Go and download the following project. There is a free pdf document. Work through the entire sample. It makes you understand all the basics you need to know about asp.net mvc framework
Mvc Music Store
And also if you create a default mvc project in visual studio, it should show you how to handle the signup form in the Register action.

Related

Pass data between Views in MVC

I'm working on a Web Application project using C# and MVC that will take in two URLs in a form and use them to create an instance of a class I have created called "ImageSwap." This model has some data (a username of the person performing the swap; two variables which hold the URLs of two images to be swapped; two variables which save the actual names of these files without all of the rest of the URL information; and two arrays which represent the file locations to check for these files). Right now, I have it so that the initial index view creates the instance of the class and passes it to the same view with the information put in through the form, submitted via POST, like so:
public ActionResult Index()
{
Ops.Operations.Models.ImageSwapModel newImageSwap = new Models.ImageSwapModel();
return View(newImageSwap);
}
[HttpPost]
public ActionResult Index(ImageSwapModel imageSwap)
{
var oldFileFound = false;
var newFileFound = false;
if (ModelState.IsValid)
{
//Perform data manipulation and set needed values
}
}
It then performs some functions on the data, such as parsing out the filename at the end of the URL, and a directory number (which is the first part of this filename, i.e. directory#_fileName.jpg). All of this works fine.
My problem is that I would like to pass this model to another view once it has data populated in all of its fields by this initial ActionResult so that I can have a verification view, which would allow the user to preview the two files side by side so that they can ensure they are swapping the appropriate images. They should then be able to hit another submit button which will initiate the actual moving/replacing of the images and be taken to a page confirming.
Is there a way to pass data from this controller to a different view? My confusion arises because I cannot create another version of an ActionResult of Index with the same input, but I do not want to have the actual swapping of the images occur without a preview and a prompt. Should I re-write my Index view so that it utilizes partial views in order to accomplish this? What is the easiest way to have data persist through multiple steps and views?
What is the easiest way to have data persist through multiple steps
and views?
Your question sounds like you're trying to achieve what you can easily do with sessions. The session object allows you to persist data between requests simply by adding it to the Session object on the HttpContext that exists within the base class that your controller extends, like so:
(Note the Serializable attribute. This allows your object to be serialized into the session object).
[Serializable]
public class ImageSwapModel {
// Your class's properties
}
Then in your controller you can do the following:
[HttpPost]
public ActionResult Index(ImageSwapModel imageSwap)
{
var oldFileFound = false;
var newFileFound = false;
if (ModelState.IsValid)
{
this.HttpContext.Session["ImageSwap"] = imageSwap;
}
}
When you want to retrieve the model you can grab it from the session like so:
var imageSwap = (ImageSwapModel)this.HttpContext.Session["ImageSwap"];
Taking it one step further:
Whilst the above will work fine, generally it's not a good practice to reference the HttpContext object directly in your code as it creates unnecessary coupling to the HttpContext object that can easily be avoided. Instead you should opt to inject an instance of the session object via Dependency Injection. Here is a similar answer that provides a basic idea as to how you can do this.
You can return different views with Models being passed to them in your one Index action like
if(some condition)
{
Return View("ViewVersion1", MyModelVersion1);
}
else
{
Return View("ViewVersion2", MyModelVersion2);
}

ASP.Net MVC Postback and Models

This is mostly a follow-up to a comment in this issu, but I don't have enough reputation to comment ...
ASP.Net MVC Postback a label value to your controller
Let's say I have a simple model:
public class SimpleClass
{
public String Label { get; set; }
public String FirstName { get; set; }
}
Label is changed based on user/client so it can't be a DataAttribute. If when posted back processing problems occur, we need to redraw the entire page. This is the crux of the problem of the previous post. The accepted solution is to do this:
#Html.DisplayTextFor(model => model.Label)
#Html.HiddenFor(model => model.Label)
#Html.EditorFor(model => model.FirstName)
That makes sense in that it works. But our models are much more complicated and extensive. This method will result in a ton of hidden fields which seems like a very dirty solution.
This brings me to JP's comment:
ASP.Net MVC Postback a label value to your controller
The solution there is to reload the model. But it's not just a reload, it's also a merge since you want to preserve any client-side data changes.
default: SimpleClass { Label="TheLabel", FirstName="Rob"}
postedback: SimpleClass { Label="", FirstName="Steve" }
we want: SimpleClass { Label="TheLabel", "FirstName="Steve" }
My question is does MVC have a good way to know what fields were postedback so it merges correctly? We would need to only merge postedback fields not blank properties.
Or is it better to just ajaxify the entire postback and not do a form submit? This avoids all model reload issues on submit.
Update
To give Pablo credit I accepted his solution. To see my simple example of his solution, check Robert Harvey's comment in the Answers below:
ASP.Net MVC Postback and Models
The main problem here is in trying to fit WebForms' PostBack concepts into MVC. There is no such thing as a stateful postback where things just automatically retain their state.
You only have ViewModels that are bound to the view, and ViewModels that are posted by the view to the Controller. They don't even necessarily need to be of the same Type. Meaning, the controller should only receive the data that the user indeed can change, not large objects with many properties that were part of the initial ViewModel but are read-only.
Labels commonly represent read-only texts and they are not editable form elements. Which is why you have to use hidden fields for that.
And yes, sometimes that implies that you have to reload the original data in the controller, and sync up with new data that you posted, which isn't necessarily a bad thing. If you bind read-only data to a view, which the user can't manually edit, you shouldn't really trust that data coming back in a post afterwards. Just because your html might try to make it read-only doesn't mean I can't manipulate the post and ultimately change your "read-only" data without you knowing.
I just read the second question you mentioned, and from the looks of it, his main problem was that he was trying to reuse the same ViewModel again, so all the data was missing and the model wasn't valid. The solution to that is indeed quite simple, ONLY post what you need, as a new ViewModel type, and have the controller take care of the rest.
[Moved from OP]
I think this is what Pablo is suggesting for those who are wondering. It seems to be a good pattern to resolve this problem.
Models:
public class SimpleClass : SimpleClassPostBack
{
public String Label { get; set; }
public SimpleClass()
{
// simulate default loading
Label = "My Label";
FirstName = "Rob";
}
}
// contains only editable by the user fields
public class SimpleClassPostBack
{
public String FirstName { get; set; }
}
Controller Actions:
[HttpGet]
public ActionResult SimpleClassExample3()
{
SimpleClass simpleClass = new SimpleClass();
return View(simpleClass);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SimpleClassExample3(SimpleClassPostBack postBackSimpleClass)
{
Boolean errorOccurred = true;
if (!errorOccurred)
{
// do whatever success action is necessary
}
// redraw the page, an error occurred
// reload the original model
SimpleClass simpleClass = new SimpleClass();
// move the posted back data into the model
// can use fancy reflection to automate this
simpleClass.FirstName = postBackSimpleClass.FirstName;
// bind the view
return View(simpleClass);
}
View:
#model SimpleClass
#{
ViewBag.Title = "Simple Class Example3";
}
<h2>Simple Class Example3</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<label for="FirstName">#Html.DisplayFor(m => m.Label)</label>
#Html.EditorFor(m => m.FirstName)
<br/>
<button>Submit</button>
}
You should only send data from the client to the server that the server can't "figure out" on its own. If the server knows what the labels were when the user first navigated to that view then if the user cannot modify them, the server will be able to know what the labels are when reloading the view.
Use hidden fields to identify the database objects. So your SimpleClass should probably have some sort of Id which you will use in the hidden input. Use the EditorFor for FirstName. Now when the form is posted, use the sent Id to find the correct SimpleClass from the database and modify its FirstName property with the value posted. The Label property will be null which is ok since you don't need to save it. Now if there's a problem in the post and you want to send the same view back like it was, you need to repopulate the Label the same way you did when the user arrived to the view for the first time. The values of Id and FirstName properties will be automatically sent back to the view with the model state.
In summary:
Only post data that is needed to identify something and what the user
can edit in that view.
Don't trust the client to send you anything valid. The user can change the values of the hidden field labels to anything.

General approach for displaying a message on any page

I have a fairly simple (to explain) requirement for my ASP.NET MVC web application:
On any page, be able to display a message based on an event that happened on a preceding page. Messages may include dynamic content, such as information entered by the user in a form submission.
Similar to this...
The approach must work in POST-REDIRECT-GET scenarios.
If the user has two browser tabs (which share session state) open on the application, then any message should only be displayed in the tab in which the related event happened.
For example:
After submitting a feedback form, a message thanking the user (by name)
When logging in, a message telling the user the date/time when they last logged in to the application
My first thought was to use a strongly-typed view with an appropriate model (with a string property) for this. However this would mean changing every single existing non-strongly-typed view to use this model, and updating all existing models to inherit from this new model.
This seems like overkill.
An alternative is to store the message in TempData:
// In my controller
TempData["Message"] = "Some kind of message";
// In my shared master view
#if (TempData["Message"] != null)
{
<div class="message">#TempData["Message"]</div>
}
Using TempData is covered in a bit more detail in this blog posting. Interestingly, the author also suggests using a custom HTTP header as an alternative. An interesting idea, but does not work with POST-REDIRECT-GET.
Is using TempData the preferred option, or is there a "better" alternative? (e.g. something more strongly typed)
My first thought was to use a strongly-typed view with an appropriate model (with a string property) for this. However this would mean changing every single existing non-strongly-typed view to use this model, and updating all existing models to inherit from this new model.
This is the only consistent, reusable, testable solution to do this that I can imagine, despite the extra work it may cause.
It is best practice to use ViewModels to communicate between View and Controllers. You can have a base View Model and all other View Models derived from that as below:
public class BaseVM
{
public string Message{ get; set;}
}
public class CreateViewModel: BaseVM
{
public string CustoomerName{ get; set;}
}
You can populate the Message property while returning the model to the controller as below:
public ActionResult Step2()
{
//Some Logic
step2Model.Message = "Yes, Success..!!";
return View(step2Model);
}
After that, on each view page, you can check if that property has something in it.You can do so as below:
#if(!string.IsNullOrEmpty(Model.Message))
{
//Show message
}
EDIT:
OP is well aware of this approach, but still keeping this answer as it has a snippet to show how to do this in code. Secondly, when it comes to use ViewModels, I agree with following comment by CodeCaster in his answer.
This is the only consistent, reusable, testable solution to do this that I can imagine, despite the extra work it may cause.
You could make a convention in your project that a message to display would always go into ViewBag.InfoMessage dynamic variable. So, in your layout file you would display it if it's passed into the view from a controller.
More strict way would be to create a base model class with InfoMessage property and derive all other models / viewmodels from that base.
To persist the message through POST-REDIRECT-GET scenario, use a session variable which you'd clear once the value is sent to the view - to avoid displaying on more than one page.
Here some code:
public class BaseViewModel
{
public string InfoMessage { get; set; }
}
public class SpecificViewModel : BaseViewModel
{
// other model properties
}
In your controller then:
SpecificViewModel vm = new SpecificViewModel();
vm.InfoMessage = Session["InfoMessage"] as string;
Session["InfoMessage"] = null;
// other code
return View(vm);
Of course your view will have strongly typed model: SpecificViewModel.

How to show/hide things in the View using role permissions?

I’m using authentication with Active Directory within an ASP .NET MVC3 web application.
I want to control what components are rendered in the view. The option I’m considering is passing in the groups the logged in user is part of from the controller, and then using a helper object to check whether the user is part of the required group. Is this the best method to achieve this? If it is, then how would I achieve the controller part?
Thanks.
Well this could be achieved if you use a correct model linked to the page (view-model, not a class from your domain), if you follow this approach, the view model should contain all the information required by the view and nothing more, since your view requires to know which controls should be visible based on the current user roles, I would create a property for each control in the view model like this:
public class MyViewModel
{
public bool ShowMycontrol1 { get; set; }
}
in your controller populate this "flags" using the current user roles, and finally in the view check for these properties in order to show or hide the required controls
This is just one way to accomplish this, I'm sure there many more
You can write an extension method. Let's say you want to check whether user is admin or not. So, you do that using extension method like this;
public static class AuthHelper
{
public static bool IsUserAdmin(this HtmlHelper helper)
{
return helper.ViewContext.HttpContext.User.IsInRole("Administrator");
}
}
i hope this helps.

ASP.NET MVC: Populating Derived Strongly Typed View with Base Strongly Typed View

In my application I have different pages: Contact Us, About Us, Home
They all have the same base elements that needs to populate the view:
Page Title
Meta Description
User Information
However on each page, they have some elements that are different:
Contact Us
Contact Information Model
Contact Form Model
About Us
Extended User Information Model
Home
Home Page Text Property
They are all routed to the same Controller Action Method because most of the functionality is similar other than populating the "extra" information dependent on page type.
So far I have done something where:
PageDetailViewData pageDetailViewData = new PageDetailViewData {Title = title, Desc = desc....}
and following this I have:
switch ((PageType)page.PageType)
{
case (PageType.Contact):
return View("ContactUsDetails", pageDetailViewData);
default:
return View(pageDetailViewData);
}
The question is how do I populate the "extra" information? I am not sure if I am going about doing this the right way. Any insight to better structure the logic flow would be appreciated.
The answer of using interfaces to imply some commonality between your view models is certainly going to help to answer some of the points in your questions.
I would however ask how wise it is to "refactor" your Action to support multiple views of differing data structures.
MVC controller actions typically represent the minimum amount of code required to gather the specific data required to generate the intended view. It's not completely uncommon for a single action to return different views of the same model data (Html view or Mobile view for example) but by varying both the structure of the data and view that will generated you introduce a few problems.
In particular you violate common best practices like the Single Responsibility Principle and make your code much more complicated to test - and Pain free testing and TDD are part of the big win with ASP.Net MVC after all.
Personally I would have a separate Action.
As far as your view models are concerned, how would you do it if this was a database?
You would have separate queries for separate data right?
A user's profile information would be queried separately from the page meta data information. This would be done for a number of reasons that could include the ability to cache certain parts of the data but not others for example.
So with the above suggestions your code might look like this (Warning: this code wasn't written in Visual Studio and is probably full of syntax issues):
public interface IMetaDataViewModel
{
PageMetaData MetaData{get; set;}
}
public class HomeViewModel : IMetaDataViewModel
{
public PageMetaData MetaData{get; set;}
public string HomePageText{get; set;}
}
//other view models go here....
public class CommonPagesController : Controller
{
private MetaDataProvider _metaProvider = new MetaDataProvider();
private PageDataProvider _pageDataProvider = new PageDataProvider();
private ContactDataProvider _contactDataProvider = new ContactDataProvider();
public ActionResult Home()
{
var viewModel = new HomeViewModel
{
MetaData = _metaProvider.GetPageMeta();
HomePageText = _pageDataProvider.GetPageData();
};
return View(viewModel);
}
public ActionResult Contact()
{
var viewModel = new ContactViewModel
{
MetaData = _metaProvider.GetPageMeta();
ContactFormData = _contactDataProvider.GetData();
};
return View(viewModel);
}
//you get the picture...
}
There are several ways you could also refactor out the generation of the view model code but thats one possible pattern.
I appreciate that this answer does have a certain amount of opinion in it but I would consider having separate actions to be best practice.
Hope that helps.
The title of your question almost gives you the answer. You can use some form of polymorphism to accomplish this. You could define a base class with the shared properties, or alternatively an interface like this:
public interface ICommonPage
{
string Title { get; }
string MetaDescription { get; }
string UserInformation { get; }
}
Then define three strongly typed ViewModel classes that all implement this interface (or derive from the base class):
ContactUsViewModel : ICommonPage
AboutUsViewModel : ICommonPage
HomeViewModel : ICommonPage
On each of those ViewModel classes, you add the extra properties that you need for those Views.
In your Controller Action, you will need to switch on PageType to select the correct ViewModel and populate it with data.
You will also need to creat three different Views (.aspx) that are strongly typed to each ViewModel class.
If you have shared rendering for the common data, you can extract that into a strongly typed UserControl (.ascx) that is typed to ICommonPage.

Categories

Resources