I'm a control developer and I'm trying to design a MVC.net control. When I researched some of the MVC controls like MVC toolkit, Telerik and DevExpress etc, I'm confuse which coding style is the popular way.
For example, Telerik has its own special coding style, just like this sample:
[Code1]
Html.Telerik().Calendar()
.Name("Calendar")
.Value((DateTime)ViewData["selectedDate"])
.MinDate((DateTime)ViewData["minDate"])
.MaxDate((DateTime)ViewData["maxDate"])
It uses dot till the end. While the DevExpress allows us using lambda expression to setting so that we can write code in the View.
[Code2]
#Html.DevExpress().GridView(
settings =>
{
settings.Name = "gvSorting";
settings.CallbackRouteValues = new { Controller = "GridView", Action = "SortingPartial" };
settings.Width = Unit.Percentage(100);
settings.Columns.Add("ContactName").SortOrder = DevExpress.Data.ColumnSortOrder.Ascending;
settings.Columns.Add("CompanyName");
settings.Columns.Add("City");
settings.Columns.Add("Region");
settings.Columns.Add("Country");
}).Bind(Model).GetHtml()
Or another option is writing code in the Action and store it in the ViewData or Model, so that the [Code1] can be like:
Html.NewWay(Model).Render()
In this way, we can write all code in the action side. So maybe users are familiar with it.
I hope if you have any ideas or experience, please feel free to talk about it.
Thanks,
Howard
As you say, there are different ways to do it. It all depends on what you want to do.
The Telerik style is known as "Fluent" notation, it's designed so that every configuration entry returns the a reference to the newly configured object, and you must guarantee you will never return null.
There is no one overriding style, people like different ways. Do whatever you think works best for you.
Related
I have an ASP.Net MVC 4 application where the user can choose a theme or a design of for their hosted one-page site (within this application). At first, I thought to do this with the built-in Areas but due to some application restrictions I've decided not to use that method. The way I thought to do it (which so far works) is to send the user to the index action of the controller, there find out which theme they have chosen and then return the appropriate view. this way I don't have the action name on the url which is nice since the url needs to be simple like: abc.com/cb/websiteID. btw, every theme/design has one view in the folder.
For some reason this method does not sit well with me and I think there should be a better way of doing this. Is there a downfall to this? Is this method a bad practice? is there a better way?
If I've left out a detail, please let me know and I'll do my best to address it.
Do you have a limited set of themes, which your users can choose from?
If so, I would consider to have a layout-per-theme instead, have a single view and dynamically switch layout based on params...
//in your controller
public ActionResult(int id) {
string layoutForThemeName = SomeService.GetThemeForUser(id);
ViewBag.LayoutName = layoutForThemeName
}
// in your view Index.cshtml
#{
Layout = ViewBag.LayoutName;
}
Do not forget that Razor let you inherit one layout from another, so you could event create base layout with script references etc. and layout for every of your themes.
In my view (asp.net mvc razor) I would like to display a description (from my model) in french or dutch based on current thread culture. Below is my actual implementation.
<td>#item.Title</td>
<td>#item.SubTitle</td>
#if (Thread.CurrentThread.CurrentCulture.Name == "fr-BE") {
<td>#item.MaterialPacking.DescriptionFr</td>
} else {
<td>#item.MaterialPacking.DescriptionNl</td>
}
<td>#item.Quantity</td>
...
I think the code clarity is not optimal but I don't think creating a helper specific for this is necessary. Are there any other possibilities?
Thanks.
UPDATE
Here is an extract of data I retrieve from my repository.
As you can see I have 2 possibilities: ...fr or ...nl
I need a specific item based on the current culture.
here is the linq:
var request = requestRepository.Find(x => x.RequestID == requestID)
.MyInclude(x => x.TransportedMaterials.Select(y => y.MaterialPacking)).FirstOrDefault();
return request.TransportedMaterials;
If you use a custom ViewModel, you can make it the controller's responsibility to populate the MaterialPacking property with the message in the correct language. That moves the code out of the view.
However, the if/else statement is still bad practice. What happens if you decide to support Spanish? Do you want to modify every one of these if statements throughout the code? You should create a service where you can pass it the key for a message and it will give you back the actual message in the current language.
So your controller code would end up saying something like this:
item.MaterialPackingDescription =
_languageService.GetDescription(item.MaterialPacking);
And your view code:
<td>#item.MaterialPackingDescription</td>
You don't need special casing (it wouldn't scale: if you were to add one more language, you'd have to go in an add a new else block everywhere you do this). The way to get localized strings is to use the built-in resource manager. Visual Studio makes this very easy... Look it up (or look up localization) in MSDN.
So your code would become:
<td>#item.Title</td>
<td>#item.SubTitle</td>
<td>#Resources.MaterialPackingDescription</td>
<td>#item.Quantity</td>
...
Note that you are also using the wrong property: For resources you should use Thread.CurrentThread.CurrentUICulture rather than CurrentCulture.
Why not perform this logic in your controller or view model. Then you wouldn't need to do it in your view.
Take a look at this blogpost about Localization.
With resource files you'll be able to keep your view cleaner because there's no need for if constructions to display messages in the correct language.
You must store your string values in App_GlobalResources, and then use it from there.
Check this article for more help
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I know a bunch of people that are really enjoying the improvements that ASP.NET MVC 2 made over the first release. I have just started to migrate our MVC 1 project over and so far areas has totally cleaned up the subfolder mess we had in our large scale application. As I dive deeper into all the improvements and changes that were made I still keep thinking to myself man it would be nice if they had x in this release. For instance, I would love it if they had some sort of dependency injection built in instead of having to use third party solutions.
My real question is now that ASP.NET MVC 2 is out in the wild, what features do want/wish the team had implemented and hope they will implement for ASP.NET MVC 3?
EDIT
Looks like dependency injection is built in for the first preview release of ASP.NET MVC 3! I like the features added so far. ASP.NET 3 preview one is out!
I think MVC 3 will not be too dramatic with it's improvements, but more steady and gradual.
The ASP.NET MVC 3 Roadmap has a snapshot of what the team are apparently looking at implementing in the next release and some of the points are very interesting.
I think my favourites from that list would probably be:
More AJAX Helpers: This'll bring the framework more in line with the Webforms world which has all these helpers already and to some degree, acts as a barrier to some people taking up the platform.
More Dependency Injection stuff - for those that want it, this is great. :)
Improved Caching support is the big win for me. Having that built right into the framework would be a great benefit and could result in some nice performance savings.
Additional ValidationAttributes wouldn't go a miss either. While the facility is great to add them, a good library of the common ones, such as Email and PropertiesMustMatch and so on.
I would like the complete removal of all magic strings.
I really wish they'd add the following:
Spark-style conditionals and loops using html tag attributes.
Updated: Visible project property to toggle compile-time validation of views.
Something to verify/validate that my routes are correct.
Membership provider solution that uses int instead of Guid for identification and allows mapping profile fields to a custom table rather than the generic but slow default.
Lambda-based helpers to avoid magic strings (currently in MvcFutures)
T4MVC template to auto-generate strongly typed helpers
Project wizards or templates to get a template that is already setup for IoC and similar concerns, preferably with a selection dialog to choose which framework to use for IoC, unit testing, etc.
Additional attributes (both filters and validation).
Hmmm, that's all I can think of right now :)
Tooling (T4 templates) to create Moq objects for unit testing would be very cool. Testing for certain objects in the framework is unnecessarily complicated, and having the ability to code-gen some of this would be very beneficial.
I would like:
Tooling
An alternative listing view using ajax e.g. using jqGrid (implementing sorting, pagination, search)
Enhancements to CRUD Pages detect entities relationships for entity framework classes, and to use another set of components based in fields type e.g. just as Dynamic Data does : )
As ASP.net MVC 3 will be .net 4 only, I'd like to see some stuff around asynchronous controllers and all the other new async/multithreading functions that .net 4 brings.
I'd like to see built-in support for things like IronRuby
MEF support would be nice.
I'd like to see a new way of handling routing, to make it easier to developer REST services. Currently I have routes like this:
context.MapRoute(null,
"api/posts",
new { controller = "Post", action = "Get" },
new { httpConstraint = new HttpMethodConstraint("GET") });
context.MapRoute(null,
"api/posts",
new { controller = "Post", action = "Insert" },
new { httpConstraint = new HttpMethodConstraint("POST") });
context.MapRoute(null,
"api/posts/{id}",
new { controller = "Post", action = "Update" },
new { httpConstraint = new HttpMethodConstraint("PUT") });
context.MapRoute(null,
"api/posts/{id}",
new { controller = "Post", action = "Delete" },
new { httpConstraint = new HttpMethodConstraint("DELETE") });
To a new person using ASP.NET MVC, it's very unintuitive to create anonymous objects to handle routing. I'd like to see it revised to something like this (and since we're using C# 4.0):
context.MapRoute("api/posts",
controller: "Post",
action: "Get",
httpMethodConstraint: HttpMethodConstraint.GET
);
context.MapRoute("api/posts",
controller: "Post",
action: "Insert",
httpMethodConstraint: HttpMethodConstraint.POST
);
context.MapRoute("api/posts/{id}",
controller: "Post",
action: "Update",
httpMethodConstraint: HttpMethodConstraint.PUT
);
context.MapRoute("api/posts/{id}",
controller: "Post",
action: "Delete",
httpMethodConstraint: HttpMethodConstraint.DELETE
);
This would make it more discoverable as well.
I'd like helpers that automatically scaffold index views. Maybe something like IndexDisplay(), IndexDisplayFor(), and IndexDisplayForModel().
I'd like templating to auto-generate buddy classes on any given model.
i also use simplicity feature like most of thing without helper such as html-helper i thing that development in asp.net MVC 3 is better way to learn MVC 3 in future.
The two things I'd like to see most are straightforward dependency injection in views, filters, etc., and (I know this is supposedly on the way with the Razor view engine) is to be able to test my views in isolation from the ASP.Net pipeline (perhaps including doctype validation and/or some type of JavaScript compiling/validation).
Here are a few other ideas:
It would be nice to be able to package up a UI component (views, templates, view models, etc.) for reuse across multiple projects. I'm guessing this is currently possible somehow, but I just don't need it badly enough to figure it out myself.
The idea of controllerless actions intrigues me, particularly from a SRP standpoint.
Better support for the Post-Redirect-Get (P/R/G) pattern... it just seems like there should be intrinsic support for this very important pattern.
more controls and helpers would be really nice, especially an (ajax) grid.
Asp.net MVC 3 Preview 1 was just announced as well at http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx
I would like to see areas assembly support (I mean many assemblies with different areas) + dynamic loading, something like plugins.
Edit:
And we have preview 1 today: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx
Anybody happy ? :>
I'm working with Visual Studio 2008 SP1 and ASP.NET MVC v1. When right clicking on a view I do not get the option "Convert to Web Application" that I would need to generate code behind .cs classes. I see that option for the actual project and folders, but not for views (aspx files). I've checked the ProjectTypeGuids to have the "right" (?) values:
{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
Any other suggestions as to what I could look for?
Thanks.
(I am aware of design implications of using code behind classes with MVC)
P.S. To do it manually all you have to do is:
Add a file with the same name as your view and the .cs (or .vb) extension, for example Index.aspx.cs. Make sure you modify your class to inherit from System.Web.Mvc.ViewPage or some other class that inherits from that.
Edit the aspx file and add to the #Page directive CodeBehind="Index.aspx.cs" and change Inherits to "MyNamespace.Views.Home.Index" (obviously you need to have the right code behind and namespace there).
Right click on the aspx file and choose Convert to Web Application. This will create the design file and also modify your .cs class and mark it as "partial".
"Convert to web application" is a project/file-level command. You can't use it on a single ASPX file.
Also, there is no alternative automated way (that I know of :-)) to add code-behind files to an ASPX file. You have to do it manually, by adding the relevant files yourself and then adding them to the .csproj.
There's no need to use 'code-behind' with ASP.NET MVC.
If you use a 'code-behind', you're not following the convention of ASP.NET MVC.
The question is, why do you want a code-behind? Answering that will help us to determine what you really need.
If you really want to do this, you can do it by mixing Webforms and ASP.NET MVC together. There are lots of resources on this, but here's just one.
The MVC development model does not need code behind.
Read a good Blog Post on this Here
If you're trying to reuse some controls, maybe a good approach is to create and render them inside a helper method and than call that method from the view.
What I'm thinking about would be something like this:
public static string HelperMethod(param_list)
{
var control = new ControlType();
//set up control properties according to param_list
//get the html as string - one way to do it would be like this
StringWriter stringWriter = new StringWriter();
HtmlTextWriter htmlWriter= new HtmlTextWriter(stringWriter);
control.RenderControl(htmlWriter);
string result= stringWriter.ToString();
}
And then call it from the view like this:
<%= HelperClass.HelperMethod(params) %>
I'm not sure if this approach will work, I don't know even if it makes sense. It's more of I hack than a proper solution. I haven't done anything like this before, it's just an idea, try to see if it helps you. You should also have in mind that ASP.NET controls usually use the ViewState for state management and that there is no such thing in ASP.NET MVC.
Main question: Is there a better way to accomplish creating a reusable control?
So the idea was to make a paging control to basically stop from having to keep typing out practically the same markup on multiple views. It's taking this:
<%= Html.ActionLink("First", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.FirstPage, amountToShow = Model.AmountToShow }))%>
|
<%= Html.ActionLink("Previous", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.PreviousPage, amountToShow = Model.AmountToShow }))%>
|
<%= Html.ActionLink("Next", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.NextPage, amountToShow = Model.AmountToShow }))%>
|
<%= Html.ActionLink("Last", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.LastPage, amountToShow = Model.AmountToShow }))%>
And turning it into this:
<%= Html.Pager("View", "Controller", "RouteName", Model, new Dictionary<String, Object> { {"parentForumId", Model.ParentForumId}}, " ") %>
Where as you can see I pass in the needed view, controller, route name, model, and a dictionary used to add request variables onto the url for the link.
What I found is that I would have to make an extension method for the HtmlHelper class and essentially take what in ASP.Net was a full class (with nice methods like CreateChildControls) and jam it all into one main method that returns a string.
Is this the preferred way of doing this? One nice thing of the ASP.Net way was markup to class as in you have the html markup tag that would translate markup properties to class properties. It generally made for cleaner mark up but admittedly "fake" html. In this situation I have a method with what could be a mile long signature pumping out html. And since I don't have a base WebControl class, every control I make will have to have method calls with the same basic needs like say CssClass or ID.
Now with that being said, I suppose I could pass in an attributes dictionary since the
HtmlHelper.GenerateRouteLink
method that I'm using calls for one anyhow, but this really seems really messy.
Is there a better way to do this?
First, its all ASP.NET...one is MVC, the other is WebForms. Took me a sec to realize what you were saying when you keept saying the "ASP.NET way". :P
The idea with an MVC is that your view is "dumb", without any real behavior outside of the absolute bare bones basics to render data. In WebForms, views were tightly bound to the behavior that rendered them and handled view events. This, while convenient, made WebForms views very difficult to unit test since view content and behavior were linked and sometimes blended.
The reason MVC views use things like HtmlHelper and AjaxHelper is to keep behavior as separated from the view as possible. Unlike a user or server control in WebForms, you can fully unit test an Html.Pager extension method, since the logic is pure code, without blending those UI concerns or being linked to a bunch of non-testable UI level types. The same general rule applies to MVC controllers to...they are just code, without being linked to events or anything like that.
It may be less convenient in the short run, as you are currently used to the old WebForms way of doing things. Give yourself some time, though, and you will likely start to realize the benefits that MVC's preferred way of doing things brings to the table. Writing a Pager extension method on HtmlHelper is indeed the preferred way to do things with MVC.
As for the mile-long signature bit...do a search (try out Bing.com!) for fluent style interfaces and HtmlHelper. The fluent style is starting to take a strong hold in environments like MVC views where you are likely to have huge signatures. The general idea is based on method chaining, kind of like jQuery, and can shorten those long signatures into a series of much shorter and more meaningful chained method calls that set up your html helper, with a final call to a .Render method or something similar.
You could put it in a partial view, instead of creating a helper.
You might want to check out Martijn Boland's Pager control for some inspiration.
Personally, for my reusable grid control I use a class that contains all information needed to generate a grid with paging, sorting, ... and I call partial views to generate the seperate elements (Pager, Column selection, pagesize selection, ...), passing the information they require to them.
This way I can easily extend the grid with custom stuff. For example I can create a Mygrid_editableTable.ascx view to show textboxes instead of just text, and add an extra column with a submit button. This while continuing to use the paging, page selection, ...
We end up using html helpers for paginators as they are easy to unit test. Pagination business requirements can be finicky.
"Show less than 35 links as numbers, then group by 20s unless there are more than 100 pages of results, in which case group by 100s...but on Thursdays, or to GoogleBot, show them as... etc."
Plus our SEO guys keep changing their mind on what shape urls get the most juice. In such a situation, something unit testable is a must!