Calling PostMethod from HTML.Actionlink - asp.net-mvc

Hi I am fairly new to MVC and facing a issue.
I have a View which lists all the countries having just 2 columns
I want column headers clickable and should sort on clicking on it
I have shown my Controller & view code below and I expect that when I click on the column header it should hit Index action method decorated with [HttpPost]
When I click the header link page just refreshes without hitting Action method I expect it to hit
Any help would be appreciated.
Here is my controller code
[HttpPost]
public ActionResult Index(string sortcolumn)
{
return View(SortedList(sortcolumn));
}
private List<Country> SortedList(string sortcol)
{
List<Country> sortedlist = new List<Country>();
switch (sortcol)
{
case "idCountry":
if ((SortOrder)ViewData["sortorder"] == SortOrder.Ascending)
{
sortedlist = db.Countries.OrderByDescending(c => c.idCountry).ToList<Country>();
ViewData["sortorder"] = SortOrder.Descending;
}
else
{
sortedlist = db.Countries.OrderBy(c => c.idCountry).ToList<Country>();
ViewData["sortorder"] = SortOrder.Ascending;
}
break;
case "Countryname":
if ((SortOrder)ViewData["sortorder"] == SortOrder.Ascending)
{
sortedlist = db.Countries.OrderByDescending(c => c.Countryname).ToList<Country>();
ViewData["sortorder"] = SortOrder.Descending;
}
else
{
sortedlist = db.Countries.OrderBy(c => c.Countryname).ToList<Country>();
ViewData["sortorder"] = SortOrder.Ascending;
}
break;
}
return sortedlist;
}
Here is my view
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<eduSmart.Data.Entities.Country>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
List of Countries</h2>
<p>
Manage list of countries on this page. You can choose your action creating, editing,
removing the country data.
</p>
<% using (Html.BeginForm("Index","Country")) { %>
Total Countries : <%: Model.Count() %>
<table>
<tr>
<th>
<%: Html.ActionLink("CountryID","Index",new { sortcolumn = "CountryID" }) %>
</th>
<th>
<%: Html.ActionLink("CountryName ", "Index", new { sortcolumn = "CountryName" })%>
</th>
<th>
</th>
</tr>
<% if (Model != null)
{ %>
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%: item.idCountry%>
</td>
<td>
<%: item.Countryname%>
</td>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id = item.idCountry })%>
|
<%: Html.ActionLink("Details", "Details", new { id = item.idCountry })%>
|
<%: Html.ActionLink("Delete", "Delete", new { id = item.idCountry })%>
</td>
</tr>
<% }
}%>
</table>
<%} %>
<p>
<%: Html.ActionLink("Create New", "Create") %>
</p>
</asp:Content>

You can't hit a post method with an Action link. One thing you could do, if all you're doing is sorting here, is change your post method to a get and change the name
Instead of
[HttpPost]
public ActionResult Index(string sortcolumn)
Have something like
public ActionResult Sort (string sortColumn)
And point your actionlink to Sort.

Related

Post parameter is null

I Have controller with following methods:
public ActionResult Create()
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult Create(Tests test)
{
test.CreateDate = DateTime.Now;
test.Author = User.Identity.Name;
TestEntities db = new TestEntities();
db.AddToTests(test);
db.SaveChanges();
return RedirectToAction("CreateQuestion", new { OrderNumber = 1, idTest = test.id });
}
[Authorize]
public ActionResult CreateQuestion(int OrderNumber,int idTest)
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult CreateQuestion(Questions question)
{
TestEntities db = new TestEntities();
db.AddToQuestions(question);
db.SaveChanges();
return RedirectToAction("CreateQuestion", new {id = question.id, t = question.Type});
}
The problem is Create methods works right. It get parameter and adds it to DB. But similar method CreateQuestion displays message about question is null.
What do I wrong?
CreateQuestion view
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<test.su.Models.Questions>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Создать вопрос
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Создать вопрос</h2>
<% using (Html.BeginForm("CreateQuestion","Test")) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Вопрос</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Type,"Тип вопроса") %>
</div>
<% // List of question types
List<SelectListItem> QuestionTypes = new List<SelectListItem>();
SelectListItem t = new SelectListItem();
t.Text = "Вопрос с вариантами ответа (флажки или радиокнопки)";
t.Value = "0";
QuestionTypes.Add(t);
t = new SelectListItem();
t.Text = "Вопрос со свободным ответом (текстовое поле)";
t.Value = "1";
QuestionTypes.Add(t);
%>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Type, QuestionTypes) %>
<%: Html.ValidationMessageFor(model => model.Type) %>
</div>
<%-- <div class="editor-label">
<%: Html.LabelFor(model => model.OrderNumber,"Порядковый номер вопроса") %>
<%: Html.EditorFor(model => model.OrderNumber) %>
<%: Html.ValidationMessageFor(model => model.OrderNumber) %>
</div>--%>
<div class="editor-label">
<%: Html.LabelFor(model => model.Question,"Текст вопроса") %>
</div>
<div class="editor-field">
<%: Html.TextAreaFor(model => model.Question,2,47,"") %>
<%: Html.ValidationMessageFor(model => model.Question) %>
</div>
<%: Html.HiddenFor(model => model.idTest) %>
<%: Html.ValidationMessageFor(model => model.idTest) %>
<%: Html.HiddenFor(model => model.OrderNumber ) %>
<%: Html.ValidationMessageFor( model => model.OrderNumber) %>
<p>
<input type="submit" value="Далее" />
</p>
</fieldset>
<% } %>
</asp:Content>
This is difficult to figure out without knowing the model. Someone else may provide a better answer, but here is the only thing I can think of for now:
If your Questions model looks like this:
public class Questions
{
int Id {get;set;}
string Name {get;set;}
string Description {get;set;}
}
What you can do, for now, is alter your controller to accept the individual parameters and create the object yourself. This might help you figure out which critical property in your Model is missing.
public ActionResult CreateQuestion(string Name, string Description)
{
//make the entity yourself
Questions newQuestion = new Questions()
{
Name = Name,
Description = Description
}
//your other code here
}
Now normally MVC is smart enough to bind your individual values in your form (view) to your model, but some critical value is missing and causing you issue. Once you've figured out what that is, you can actually restore your controller back to accepting only a Questions object.
Sorry I couldn't help you more.
Good Luck.

MVC file uploader returns a null

I am basing my solution on this article;
http://dotnetslackers.com/articles/aspnet/ASP-NET-MVC-and-File-Uploads.aspx
However when I try to upload a picture I get a null instead of a filename.
My view looks like this;
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<SHP.Models.HrViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit Employee
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<fieldset>
<legend>Add details to the selected employee</legend>
<p>The photo you select for an employee will appear on MNet.</p>
<p>The qualifications you add for an employee will appear on their business cards when required.</p>
<% using (Html.BeginForm("EditEmployee", "HumanResources", FormMethod.Post,
new{enctype = "multipart/form-data"}))
{%>
<%: Html.AntiForgeryToken() %>
<%: Html.ValidationSummary(true) %>
<%: Html.EditorFor(model => model.EmployeeSelector) %>
<% if (Model.SelectedEmployee != null)
{ %>
<%: Html.HiddenFor(model => model.SelectedEmployee.EmployeeId) %>
<%: Html.HiddenFor(model => model.EmployeeName) %>
<table class="groupBorder" style="margin-top:15px; width:617px;">
<tbody>
<tr>
<th colspan="2">Add Details for <%: Model.EmployeeName %></th>
</tr>
<tr>
<td style="text-align: right;">
<%: Html.LabelFor(model => model.SelectedEmployee.Photo)%>
</td>
<td>
<input type="file" id="Picture" name="Picture" />
</td>
</tr>
<tr>
<td style="text-align: right;">
<%: Html.LabelFor(model => model.SelectedEmployee.Qualifications)%>
</td>
<td>
<%: Html.TextBoxFor(model => model.SelectedEmployee.Qualifications, new {style = "width:500px;"})%>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center;padding-top:20px;">
<input type="submit" value="Save" id="btnSubmit" /></td>
</tr>
</table>
<% } %>
<% } %>
</fieldset>
</asp:Content>
When you click on the Save button you go to this controller action;
[HttpPost]
[Authorize(Roles = "Administrator, HumanResources, ManagerAccounts, ManagerIT")]
[ValidateAntiForgeryToken]
[ValidateOnlyIncomingValues]
public ActionResult EditEmployee(HrViewModel hrvm)
{
if (ModelState.IsValid)
{
if (hrvm.SelectedEmployee == null
|| hrvm.EmployeeSelector.SearchTextId != hrvm.SelectedEmployee.EmployeeId)
{
return this.RedirectToAction(
"EditEmployee", new { employeeId = hrvm.EmployeeSelector.SearchTextId });
}
if (hrvm.SelectedEmployee.Picture.HasFile())
{
var destinationFolder = Server.MapPath("/Users");
var postedFile = hrvm.SelectedEmployee.Picture;
var fileName = Path.GetFileName(postedFile.FileName);
var path = Path.Combine(destinationFolder, fileName);
postedFile.SaveAs(path);
hrvm.SelectedEmployee.Photo = path;
}
var emp = Employee.GetEmployee(hrvm.SelectedEmployee.EmployeeId);
this.TryUpdateModel<IEmployeeHrBindable>(emp, "SelectedEmployee");
emp.Update();
this.TempData["Message"] = string.Format(
"At {0} Details updated for {1}", DateTime.Now.ToString("T"), hrvm.EmployeeName);
return this.View(hrvm);
}
return this.View(new HrViewModel());
}
So what am I doing wrong?
By default, MVC3 performs model binding based on the Name attribute of the input elements in your view.
To get file upload data, use the HttpPostedFileBase class as a parameter to your ActionResult and call the parameter 'file'.
[HttpPost]
[Authorize(Roles = "Administrator, HumanResources, ManagerAccounts, ManagerIT")]
[ValidateAntiForgeryToken]
[ValidateOnlyIncomingValues]
public ActionResult EditEmployee(HrViewModel hrvm, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
if (hrvm.SelectedEmployee == null
|| hrvm.EmployeeSelector.SearchTextId != hrvm.SelectedEmployee.EmployeeId)
{
return this.RedirectToAction(
"EditEmployee", new { employeeId = hrvm.EmployeeSelector.SearchTextId });
}
if (file.ContentLength > 0)
{
hrvm.SelectedEmployee.Picture = file;
var destinationFolder = Server.MapPath("/Users");
var postedFile = hrvm.SelectedEmployee.Picture;
var fileName = Path.GetFileName(postedFile.FileName);
var path = Path.Combine(destinationFolder, fileName);
postedFile.SaveAs(path);
hrvm.SelectedEmployee.Photo = path;
}
var emp = Employee.GetEmployee(hrvm.SelectedEmployee.EmployeeId);
this.TryUpdateModel<IEmployeeHrBindable>(emp, "SelectedEmployee");
emp.Update();
this.TempData["Message"] = string.Format(
"At {0} Details updated for {1}", DateTime.Now.ToString("T"), hrvm.EmployeeName);
return this.View(hrvm);
}
return this.View(new HrViewModel());
}
(So if you could grab the image data using model binding, it would have been located at hrvm.Picture instead of hrvm.SelectedEmployee.Picture)
In your view use the following instead and the default model binding should work:
<%: Html.TextBoxFor(model => model.SelectedEmployee.Photo, new { type = "file" }) %>
That is assuming SelectedEmployee.Photo is of type HttpPostedFileBase.
The reason it isn't working at the moment is that the default model binder will be trying to find a property called Picture directly on the model, because that's the name of your file input. It won't find it, because Picture is a property of SelectedEmployee.
Changing it to what I've suggested above generates the correct id and name for the file input in the markup so when posted back has the correct path. This means the default model binder is then able to map between the form post value and the property.

Cannot refresh page after deleting a row in a grid

Can anyone see why this code doesn't work?
I know that someone will notice that I am using Delete links and I should be using a DELETE verb rather than a POST, but I have not been able to resolve that issue, even with the help of SO.
No the issue here is that I click on delete, the underlying data gets deleted OK, but after I delete the data, when I try to redirect to the Payroll GET method, it does not get called and as a result the screen does not get refreshed.
So here is the code on the Controller;
[HttpGet]
[Authorize(Roles = "Administrator, AdminAccounts, ManagerAccounts")]
public ActionResult Payroll()
{
if ((SessionObjects.PeriodStartDate > DateTime.MinValue) && (SessionObjects.PeriodEndDate > DateTime.MinValue))
if (SessionObjects.PayrollSelectedEmployeeId == 0)
return View(new PayrollViewModel()
{
PeriodStartDate = SessionObjects.PeriodStartDate,
PeriodEndDate = SessionObjects.PeriodEndDate
});
else
return View(new PayrollViewModel(
SessionObjects.PeriodStartDate,
SessionObjects.PeriodEndDate,
SessionObjects.PayrollSelectedEmployeeId
));
return View();
}
[HttpPost]
[Authorize(Roles = "Administrator, AdminAccounts, ManagerAccounts")]
public ActionResult Payroll(PayrollViewModel _pvm)
{
if (ModelState.IsValid)
{
SessionObjects.PeriodStartDate = _pvm.PeriodStartDate;
SessionObjects.PeriodEndDate = _pvm.PeriodEndDate;
if (_pvm.SearchTextId > 0)
SessionObjects.PayrollSelectedEmployeeId = _pvm.SearchTextId;
return RedirectToAction("Payroll");
}
return View(_pvm);
}
//[AcceptVerbs(HttpVerbs.Delete)]
[HttpPost]
[Authorize(Roles = "Administrator, AdminAccounts, ManagerAccounts")]
public RedirectToRouteResult Delete(int id)
{
EmployeeOtherLeaf.Delete(id);
return RedirectToAction("Payroll");
}
Part of the View and Editor Template;
<table class="groupBorder">
<tr>
<th></th>
<th>Leave Type</th>
<th>Notes</th>
<th>Day Amount</th>
<th>Date</th>
<th>Approver</th>
</tr>
<%: Html.EditorFor(x => x.LeaveList)%>
</table>
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SHP.WebUI.Models.Leave>" %>
<%# Import Namespace="SHP.WebUI.HtmlHelpers" %>
<%# Import Namespace="SHP.Models" %>
<%: Html.RowStyle(Model.RowColour) %>
<tr>
<td style="background-color:White;">
<%-- Ajax Delete --%>
<% if(Model.LeaveId > 0) { %>
<%: Html.DeleteEmployeeOtherLeave()%>
<%} %>
</td>
<td><%: Model.LeaveType %></td>
<td><%: Model.Notes %></td>
<td><%: Model.DayAmount %></td>
<td><%: String.Format("{0:ddd MMM d yyyy}", Model.Date)%></td>
<td><%: Model.ApproverName %></td>
</tr>
</tbody> <%-- Leave this here, it closes from the above Html.RowStyle!--%>
HTML Helper method;
public static MvcHtmlString DeleteEmployeeOtherLeave(this HtmlHelper<Leave> html)
{
var leave = html.ViewData.Model;
return html.RouteLink(
"Delete",
"Default",
new {id = leave.LeaveId, action = "Delete" },
new { onclick = "return DeleteRow(this);" }
);
}
You seem to be invoking the Delete action using AJAX inside the DeleteRow javascript function (which you haven't shown). You cannot redirect in AJAX requests. That's the whole point them: do not refresh the entire browser but only portions of it.
If you wanted to perform a full redirect inside the success callback of your AJAX call you could use the window.location.href property, like this:
success: function(result) {
window.location.href = '/somecontroller/Payroll';
}
Now of course doing something like this is meaningless. I would simply use a standard HTML form which will post top the Delete action and not use any javascript at all:
<% if(Model.LeaveId > 0) { %>
<% using (Html.BeginForm("Delete", "Home", new { id = leave.LeaveId })) { %>
<button type="submit">Delete</button>
<% } %>
<% } %>
Now when the form is submitted the Delete action will be invoked which will perform the actual delete and redirect the browser to the Payroll action => pretty standard HTTP dialogue.
And if you decide to go this way you even get a bonus: you could decorate your controller action with the [HttpDelete] attribute and use a technique on the client :
<% if(Model.LeaveId > 0) { %>
<% using (Html.BeginForm("Delete", "Home", new { id = leave.LeaveId })) { %>
<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
<button type="submit">Delete</button>
<% } %>
<% } %>
and then:
[HttpDelete]
[Authorize(Roles = "Administrator, AdminAccounts, ManagerAccounts")]
public RedirectToRouteResult Delete(int id)
{
EmployeeOtherLeaf.Delete(id);
return RedirectToAction("Payroll");
}
Under the hood it's not a real DELETE HTTP verb since browsers do not support it for forms but it simulates it using a hidden field which ASP.NET MVC understands and is capable to properly redispatch the request to the corresponding action.

How to decouple relational MVC data

Consider this Scenario:
I want to build an MVC application for Northwind Database. I want to have a view that list some orders and I want to create links for CustomerID and EmployeeID and a details link for [OrderDetails] so that when a user clicks any of these links related data will appear in the same page.
My problem is how to decouple this data that is interrelated into views and controllers that show related data in a page, and controllers responsible for individual parts of the information.
Also, how do I configure routing for this sample?
<table width="500px">
<tr>
<th></th>
<th>
OrderID
</th>
<th>
CustomerID
</th>
<th>
EmployeeID
</th>
<th>
OrderDate
</th>
<th>
RequiredDate
</th>
<th>
ShippedDate
</th>
<th>
ShipVia
</th>
<th>
OrderDetails
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id=item.OrderID }) %> |
<%: Html.ActionLink("Details", "Details", new { id=item.OrderID })%> |
<%: Html.ActionLink("Delete", "Delete", new { id=item.OrderID })%>
</td>
<td>
<%: item.OrderID %>
</td>
<td>
<%: item.CustomerID %>
</td>
<td>
<%: item.EmployeeID %>
</td>
<td>
<%: String.Format("{0:g}", item.OrderDate) %>
</td>
<td>
<%: String.Format("{0:g}", item.RequiredDate) %>
</td>
<td>
<%: String.Format("{0:g}", item.ShippedDate) %>
</td>
<td>
<%: item.ShipVia %>
</td>
<td>
<%: Html.ActionLink("OrderDetails", "GetOrderDetails", new { id = item.OrderID })%>
</td>
</tr>
<% } %>
</table>
<p>
<%: Html.ActionLink("Create New", "Create") %>
</p>
<div>
<p>
<% Html.RenderPartial("GetOrderDetails"); %>
</p>
<%--<uc1:GetOrderDetails ID="GetOrderDetails1" runat="server" />--%>
</div>
and Order Details partial view:
<table>
<tr>
<th></th>
<th>
OrderID
</th>
<th>
ProductID
</th>
<th>
UnitPrice
</th>
<th>
Quantity
</th>
<th>
Discount
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id=item.OrderID }) %> |
<%: Html.ActionLink("Details", "Details", new { id=item.OrderID })%> |
<%: Html.ActionLink("Delete", "Delete", new { id=item.OrderID })%>
</td>
<td>
<%: item.OrderID %>
</td>
<td>
<%: item.ProductID %>
</td>
<td>
<%: String.Format("{0:F}", item.UnitPrice) %>
</td>
<td>
<%: item.Quantity %>
</td>
<td>
<%: item.Discount %>
</td>
</tr>
<% } %>
</table>
<p>
<%: Html.ActionLink("Create New", "Create") %>
</p>
global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default2", // Route name
"{controller}/{action}/{OrderId}/{CustomerID}", // URL with parameters
new { controller = "NorthwindOrders", action = "Index", OrderId = UrlParameter.Optional, CustomerID = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Given this structure; how I can display order details under the order list when any of the OrderDetails links are clicked?
And, why is the URL displayed like this when I click on OrderDetails links:
http://localhost:49444/NorthwindOrders/GetOrderDetails?id=10250
I want the URL to display this way:
http://localhost:49444/NorthwindOrders/GetOrderDetails/10250
For your routing question:
if you set up a route like so:
routes.MapRoute(
"orderdetails", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "NorthwindOrders", action = "GetOrderDetails", id = UrlParameter.Optional, CustomerID = UrlParameter.Optional } // Parameter defaults
);
It will build the URL in the fashion you're wanting.
(Alternatively, you can rename the parameter to your GetOrderDetails action to string OrderId and it will find the route that formats the URL the way you want it.)
As far as your main question:
How do I 'dynamically' load content on the page based on clicks to links?
There are two ways to approach this:
Post back pages.
AJAX / Dynamic loading of data and elements in the HTML on your page.
In the post-back scenario:
In this scenario your links would all go to actions that build a model that includes the orderlist from your main page, and for the details of the specific order you clicked you'd populate your model with specifics for that order. Then your ActionResult return is the same view (or one that looks the same at least), and your view would use the PartialView Html helper to render the details.
OrderViewModel:
public class OrderViewModel
{
public IList<Order> Orders {get;set;}
public OrderDetail Details {get;set;}
}
OrderView.aspx:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<OrderViewModel>" %>
<%:Html.DisplayFor(m=>m.Orders)%> <%-- Displays the Table above listing orders --%>
<%:Html.DisplayFor(m=>m.Details)%> <%-- Displays your custom view of the details --%>
OrderController:
...
public ActionResult List()
{
var model = new OrderViewModel { Orders = GetAllOrders(), Details = null };
return View("OrderView", model);
}
public ActionResult GetOrderDetails(string OrderId)
{
var model = new OrderViewModel { Orders = GetAllOrders(), Details = GetOrder(OrderId) };
return View("OrderView", model);
}
...
In the Ajax scenario:
The Ajax scenario is essentially the same except that you hide the server round-trip in an ajax call, and then reload the page, or just a div with the content you want from the html (or JSON) in the return data of the ajax call.
The advantage of the Ajax approach is that you could specify a different Action on a different Controller for the various parts of the page you wanted to update.
Nima,
you can do it via partial views or render action, and json to display data
the basic example is as example here:
http://www.asp.net/mvc/tutorials/iteration-7-add-ajax-functionality-cs
or very popular option is display action for the task in jquery.dialog()
depends on you what way you want to proceed
cpo
revised:
My bad.
From logic point of view, it is as this:
It depends only on you, which way you want to go.
(From my point of view)
Benefits of separating the logic is :
simple to understand as controller is related only to actions for eg: orders
Can be used on more places if you need
Easy to test only small items, eg one testcase/fixture to controller for only orders
Usefull for more complicated projects
On the other hand
Keep everything in one controller and split the logic by regions
Eveything is together, easy to see other methods and what they do
Hope this is what you were looking for
cpo

Why can't an ASP.NET MVC strongly typed view use an interface?

Why can't I use this interface to create a strongly typed view?
public interface IAmAnAsset
{
int assetID { get; }
String assetTag { get; set; }
int? AddedBy { get; set; }
DateTime addedDate { get; set; }
int? LocationId { get; set; }
DateTime? purchasedDate { get; set; }
int? purchasedby { get; set; }
DateTime? disposalDate { get; set; }
int assetModelId { get; set; }
int? employeeId { get; set; }
float? depreciated { get; set; }
IAmAComputer Computer { get; }
}
When I take that exact item and convert to an abstract class, it lets me create a strongly typed view.
I'm new but I would imagine there's something I'm missing, ASP.NET MVC can work with interfaces, right?
Here's the specific class in the persistence layer I'm trying to make use of to create a strongly typed view.
public class ModelAsset : BufferedLinqEntity2<LqGpsDataContext, asset>, AssetManagementModel.IAmAnAsset
{
...
}
I'm trying to create my first MVC view.
ASP.NET works perfectly fine with interfaces:
public interface IAmAnAsset
{
int AssetID { get; set; }
}
public class AmAnAsset : IAmAnAsset
{
public int AssetID { get; set; }
}
public class HomeController : Controller
{
public ActionResult Index()
{
IAmAnAsset model = new AmAnAsset { AssetID = 10 };
return View(model);
}
}
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IAmAnAsset>" %>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<p><%= Model.AssetID %></p>
</asp:Content>
So what I wound up doing is temporarily changing IAmAnAsset to an abstract class long enough so that the Create View drop down had it available,used that to create the View, then switched it back so the persistance/database layer would compile again.
Here's what it generated for me:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<AssetManagementModel.IAmAnAsset>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Assets
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>ListAll</h2>
<table>
<tr>
<th></th>
<th>
assetID
</th>
<th>
assetTag
</th>
<th>
AddedBy
</th>
<th>
addedDate
</th>
<th>
LocationId
</th>
<th>
purchasedDate
</th>
<th>
purchasedby
</th>
<th>
disposalDate
</th>
<th>
assetModelId
</th>
<th>
employeeId
</th>
<th>
depreciated
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%= Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) %> |
<%= Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ })%>
</td>
<td>
<%= Html.Encode(item.assetID) %>
</td>
<td>
<%= Html.Encode(item.assetTag) %>
</td>
<td>
<%= Html.Encode(item.AddedBy) %>
</td>
<td>
<%= Html.Encode(String.Format("{0:g}", item.addedDate)) %>
</td>
<td>
<%= Html.Encode(item.LocationId) %>
</td>
<td>
<%= Html.Encode(String.Format("{0:g}", item.purchasedDate)) %>
</td>
<td>
<%= Html.Encode(item.purchasedby) %>
</td>
<td>
<%= Html.Encode(String.Format("{0:g}", item.disposalDate)) %>
</td>
<td>
<%= Html.Encode(item.assetModelId) %>
</td>
<td>
<%= Html.Encode(item.employeeId) %>
</td>
<td>
<%= Html.Encode(item.depreciated) %>
</td>
</tr>
<% } %>
</table>
<p>
<%= Html.ActionLink("Create New", "Create") %>
</p>
</asp:Content>

Resources