Best way to access ViewData value from jQuery method in ASP.NET MVC2 - asp.net-mvc-2

I want to access a public property called UserType from within jQuery method which is filled with the data from database call in a controller method.
The same property value needs to be set from multiple controller methods. I filled the data in ViewData and tried to access it in jquery method as mentioned below:
TestController.cs:
[Authorize(Roles = "Root")]
public ActionResult Index()
{
var user = _dbService.GetUser(_profile.UserName);
ViewData["UserType"] = user.UserType;
}
index.aspx:
<% var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); %>
<script type="text/javascript">
$(function () {
var userType = <%= serializer.Serialize(ViewData["UserType"]) %>;
alert(userType);
});
</script>
I am able to access the UserType value successfully, but I need to use the below mentioned code in all the controller action methods.
ViewData["UserType"] = user.UserType;
which is not a good design practice.
Can anyone help me know any other best alternative to manage the above mentioned change with some sample code?

Related

Facebook c# sdk mvc3 canvas issue with CanvasAuthorize

I'm creating a mvc3 canvas app using facebook c# sdk
The method name is create.
I also do a post and have another create method with [HttpPost] attribute.
When I add the [CanvasAuthorize(Permissions = ExtendedPermissions)] attribute to both the create methods, and a link from another page calls this create method, normally the get method should get called but in this case the post method gets called
But if I comment the post method then it goes to the get method.
Any ideas how to solve this.
Thanks
Arnab
This is because of the canvas authorization posting the access token into the page. The only way around it I've found is to create a different action that deals the post and use that action inside the view as post target. It will look something like this:
// /MyController/MyAction
// Post and Get
[CanvasAuthorize(Permissions = ExtendedPermissions]
public ActionResult MyAction(MyModel data)
{
MyModel modelData = data;
if(data==null)
{
modelData = new MyModel();
}
else
{
modelData = data;
}
return View(modelData);
}
// /MyController/MyActionPost
// POST only
[HttpPost]
[CanvasAuthorize(Permissions = ExtendedPermissions]
public ActionResult MyActionPost(MyModel data)
{
if(Model.IsValid)
{
//Processing code with a redirect at the end (most likely)
}
else
{
return View("MyAction", data);
}
}
Then in your MyAction view:
#using (Html.BeginForm("MyActionPost", "MyController"))
{
<!-- Form items go here-->
<inpuy type="submit" value="Submit" />
#Html.FacebookSignedRequest()
}
I have the same issue. It was doing a GET before, then suddenly when browse to an action with [CanvasAuthorize(Permissions = ExtendedPermissions)] attribute, it's doing a POST instead of a GET.

ASP .NET MVC 2 - How do I pass an object from View to Controller w/ Ajax?

I have an object MainObject with a list of objects, SubObjects, among other things. I am trying to have the user click a link on the View to add a new SubObject to the page. However, I am unable to pass the MainObject I am working with into the Action method. The MainObject I currently receive is empty, with all its values set to null. How do I send my controller action the MainObject that was used to render the View originally?
The relevant section of the view looks like this:
<div class="editor-list" id="subObjectsList">
<%: Html.EditorFor(model => model.SubObjects, "~/Views/MainObject/EditorTemplates/SubObjectsList.ascx")%>
</div>
<%: Ajax.ActionLink("Add Ajax subObject", "AddBlanksubObjectToSubObjectsList", new AjaxOptions { UpdateTargetId = "subObjectsList", InsertionMode = InsertionMode.Replace })%>
The relevant function from the controller looks like this:
public ActionResult AddBlanksubObjectToSubObjectsList(MainObject mainobject)
{
mainobject.SubObjects.Add(new SubObject());
return PartialView("~/Views/MainObject/EditorTemplates/SubObjectsList.acsx", mainobject.SubObjects);
}
I ended up with the following:
View:
<div class="editor-list" id="subObjectsList">
<%: Html.EditorFor(model => model.SubObjects, "~/Views/MainObject/EditorTemplates/SubObjectsList.ascx")%>
</div>
<input type="button" name="addSubObject" value="Add New SubObject" onclick="AddNewSubObject('#SubObjectList')" />
Control:
public ActionResult GetNewSubObject()
{
SubObject subObject= new SubObject();
return PartialView("~/Views/TestCase/EditorTemplates/SubObject.ascx", subObject);
}
And, finally, I added this JQuery script:
function AddNewSubObject(subObjectListDiv) {
$.get("/TestCase/GetNewSubObject", function (data) {
//there is one fieldset per SubObject already in the list,
//so this is the index of the new SubObject
var index = $(subObjectListDiv + " > fieldset").size();
//the returned SubObject prefixes its field namess with "[0]."
//but MVC expects a prefix like "SubObjects[0]" -
//plus the index might not be 0, so need to fix that, too
data = data.replace(/name="\[0\]/g, 'name="SubObject[' + index + "]");
//now append the new SubObject to the list
$(subObjectListDiv).append(data);
});
}
If someone has a better way to do this than kludging the MVC syntax for nested objects onto a returned View using JQuery, please post it; I'd love to believe that there is a better way to do this. For now, I'm accepting my answer.

Creating a generic edit view with ASP.NET, MVC, and Entity Framework

In my database, I have 40 tables that contain only an ID number and a name. My database is accessed using Entity Framework. While I have no trouble editing them each by generating a strongly-typed view and postback methods for each object, I would like to create a more generic method and view for viewing and editing these objects.
I am currently using the following code to access each object. In this case, it is for an object of 'AddressType':
public ActionMethod EditAddressType(int ID)
{
var result = database.AddressType.Single(a => a.ID == ID);
View(result);
}
[HttpPost]
public ActionMethod EditAddressType(int ID, FormCollection formValues)
{
var result = database.AddressType.Single(a => a.ID == ID);
UpdateModel(result);
database.SaveChanges();
return View("SaveSuccess");
}
The view 'EditAddressType' is strongly typed and works fine, but there's a lot of repeated code (one instance of this for each object). I've been told that I need to use reflection, but I'm at a loss for how to implement this. My understanding is that I need to retrieve the object type so I can replace the hardcoded reference to the object, but I'm not sure how to get this information from the postback.
I've had success binding the information to ViewData in the controller and passing that to a ViewPage view that knows to look for this ViewData, but I don't know how to postback the changes to a controller.
Thanks for any help you can give me!
If you are going to edit the object you don't need to refetch it from the database in your POST action. The first thing would of course be to abstract my data access code from the controller:
public class AddressesController: Controller
{
private readonly IAddressesRepository _repository;
public AddressesController(IAddressesRepository repository)
{
_repository = repository;
}
public ActionMethod Edit(int id)
{
var result = _repository.GetAddress(id);
return View(result);
}
[HttpPut]
public ActionMethod Update(AddressViewModel address)
{
_repository.Save(address);
return View("SaveSuccess");
}
}
You will notice that I have renamed some of the actions and accept verbs to make this controller a bit more RESTFul.
The associated view might look like this:
<% using (Html.BeginForm<AddressesController>(c => c.Update(null))) { %>
<%: Html.HttpMethodOverride(HttpVerbs.Put) %>
<%: Html.HiddenFor(model => model.Id) %>
<%: Html.TextBoxFor(model => model.Name) %>
<input type="submit" value="Save" />
<% } %>
As far as the implementation of this IAddressesRepository interface is concerned, that's totally up to you: Entity Framework, NHibernate, XML File, Remote Web Service call, ..., that's an implementation detail that has nothing to do with ASP.NET MVC.

Controller as ascx factory - bad idea?

I'm trying to create something like *.ascxs' factory.
Scenario:
I would like to render controls which depends on model, which i've passed to partialView.
I'd like to achieve something like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyAbstractModel>" %>
<%= Model.Property1 %>
<!-- other more sophisticated displays on model -->
<% Html.RenderAction("RenderControl", "Factory", new { model = Model}); %>
FactoryController:
public ActionResult RenderControl(object model) {
if (model.GetType() == typeof(Model1) {
return RenderPartial("Partial2", model);
} else {
return RenderPartial("Partial1", model);
}
}
I'd like to know is there any better way to cope with such situation. I suppose It's not the most efficient method to build web page in ASP.MVC 2.
If this method is acceptable, how can i restrict access to such controller? I would like to use this class only on server side and only by ascxs' pages
Use the ChildActionOnly() attribute to restrict access to your actions.
What you are trying to do is already builtin to MVC: Html.DisplayFor()
See: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

Where and how to load dropdownlists used in masterpage

I'm new to MVC!
I am trying to use two DropDownLists (Cities, Categories) in a PartialView that will be used in MasterPage, meaning they will be visble all the time.
I tried to load them in HomeCOntroller, but that didn't work. I got an Exception.
I read something about making a baseController that the other controllers will inherit from, I have tried that, kind of, but I guess i'm doing something wrong.
This is the only code I got today:
Masterpage
<% Html.RenderPartial("SearchForm"); %>
PartialView (SearchForm.ascx)
<% using (Html.BeginForm("Search", "Search")) { %>
<% } %> // dont know why I need two BeginForms, if I dont have this the other form won't trigger at all! Weird!
<% using (Html.BeginForm("Search", "Search", FormMethod.Get)) { %>
<%= Html.DropDownList("SearchForm.Category", new SelectList(ViewData["Categories"] as IEnumerable, "ID", "Name", "--All categories--")) %>
<%= Html.DropDownList("Search.City", Model.Cities, "--All cities--") %>
<input name="search" type="text" size="16" id="search" />
<input type="submit" id="test" title="Search" />
<% } %>
Two question:
Where and how to load the DropDownLists is the problem. I have tried to load it in the HomeController, but when go to another page then it says that the DDLs is empty and I get a Excecption.
Why do I have to use two forms for the ActionMethod to trigger ?
Hope anyone can help me out!
It sounds like you're only setting the property for a single action result. The Model.Cities data will have to be populated for every single view that needs to use it.
One solution would be to move the population of it to an ActionFilter
public class CityListAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext) {
var result = filterContext.Result as ViewResult;
result.ViewData.Model = //populate model
base.OnActionExecuted(filterContext);
}
}
and then add the filter to your controller
[CityList]
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
}
As for the two forms issue, there should be no reason that i can think of that you need an empty form.
Take a look at the html that's being output and make sure it's ok. Also check the action is being generated correcly
Better way to do this, is to create something like MasterController and have action method on it like this:
[ChildActionOnly]
public ActionResult SearchForm()
{
//Get city data, category data etc., create SearchFormModel
return PartialView(model);
}
I recommend you create strongly typed view (SearchForms.ascx of type ViewUserControl<SearchFormModel>). Also it may be a good idea to have a model like this:
public class SearchViewModel
{
public IList<SelectListItem> Cities { get; set; }
public IList<SelectListItem> Categories { get; set; }
}
and use a helper like this: http://github.com/Necroskillz/NecroNetToolkit/blob/master/Source/NecroNet.Toolkit/Mvc/SelectHelper.cs to convert raw data to DDL friendly format beforehand.
In any case, you now use Html.RenderAction() instead of Html.RenderPartial() and specify you want "SearchForm" action from "MasterController".