In my web application I have a treeview with documents. The NavigateUrl of a treenode looks like this:
viewDocument.aspx?id=1&doctype=type
In the load event of ViewDocument.asp.cs I check whether id and doctype are set. If so, check doctype has a valid value and check the id is a number. After that, i create a document object. Then I call it's Load(int id) function which will load all the data in the object. If the id doesn't exists in the database the return value is false, otherwhise true.
Is it possible to use MVC pattern? And if so, how do I start?
There is an official ASP.NET MVC framework. Check it out here. You can read up the tutorials there to get you started.
It is, but MVC is the second issue you have to address.
It would make sense if you used URL rewriting here to rewrite your urls into this template:
documents/type/id
Here is a good blog post on how to enable URL rewriting for your site hosted in IIS7:
http://blogs.iis.net/bills/archive/2008/05/31/urlrewrite-module-for-iis7.aspx
Once you have that in place, MVC is an EXCELLENT candidate for handing this scenario. You would simply declare a route with this pattern:
{controller}/{action}/{id}
The controller would be a class (most likely, DocumentsController), the action would be the type in this case. You don't have to use that, you could use a type, but then you would have to set a default action when setting up the route. Finally, the id would be a parameter into the method that is specified by action.
Start by looking into what the MVC pattern is and what it buys you. To really use the MVC pattern, and not just superficially implement some framework, you will need to get your hands around the concept rather than just reading through the framework's API.
Some of the things MVC can buy you (though not exhaustive):
- decoupling actual display from flow control and business logic
- all the -ity's:
modularity
readability
maintainability
testability
Though to get all these advantages, you have to understand the MVC concept and apply it correctly, not just arbitrarily include a framework in your project and then expect everything to go right.
Here's a good starting point for MVC:
http://en.wikipedia.org/wiki/Model-view-controller
Related
Our Aspnet Core 2.2 app needs to implement the front-controller design pattern to select an arbitrary controller based on the app's internal logic. We are not as concerned with selecting an action because we intend to be as RESTful as possible with GET, POST, DELETE, etc. Here is an example of what we want to do:
Given a request to http://example.com/DomainObjectX/, one customer's business rules might use the DomainObjectXController, but another customer's business rule might provide CustomDomainObjectXController. We do not want to redirect the request but simply use a different controller to handle it the same URL.
Can custom middleware choose an arbitrary controller? I cannot find any examples where middleware does all the routing or passes the request along to the default route. My google-fu does not get me there.
Or should we use the application/controller model to select an a controller based on our app's business rules? Can someone point to an example that does that?
Or should we implement our own MatcherPolicy? I have not seen any examples that do this.
Any and others would probably work, but I'm not sure how/when to specify the arbitrary controller. So many things to learn ...
Coming from a long period of WebForms development, I recently began working with MVC. One thing that struck me, is that since controller methods are not called directly from code, Visual Studio won't pick up any references to them.
I understand the reason why there is no reference count, but it can be problematic sometimes. Let's say I rewrite a controller method to accomodate some new requirement, perhaps a certain call to the method needs additional data or a modified result. But perhaps that method, or endpoint if you will, is being called from several places, and the change I made breaks the result handling for those other calls. I would like to be able to easily find all the code in my solution, which is going to invoke the endpoint.
Currently I tend to copy the method name and perform a regular text search in the entire solution, which works rather well as long as the method name isn't too generic. If the method name is "Index", it can be a long day.
Are there any recommendations on how to simplify this, such as coding conventions, plugins or otherwise? I.E. how can I locate from where the endpoint will be invoked?
I currently use Visual Studio 2017 Enterprise, but solutions working in other versions as well are preferred - to make the answer useful for as many as possible.
Thanks in advance / Culme
UPDATE: I learned a lot based on the comments and replies I got. Apart from what is mentioned below, I also decided to try and keep my controller method names unique and identifiable, to simplify finding where they are being used. As an example, instead of just "Index", I'll try to use "Fidgets_IndexController" or something similar. That way, a simple text search will go a long way for locating calling code.
Controller methods are not directly referenced from any part of the code (therefore 0 references), but they are dynamically invoked based on RouteTable which maps controller methods on startup RouteConfig.RegisterRoutes(RouteTable.Routes); in global.asax "implicitly" which would map them as /controller_name/action_name or these can be changed by either editing
RouteConfig.RegisterRoutes(RouteCollection routes) or using attributes:
[Route("myAction")]
public ActionResult MyAction() {
...
}
which would bind it to /myAction (without controller name)
further reading:
MSDN - Understanding MVC Application Execution Process
Lifecycle of an ASP.NET MVC 5 Application
ASP.NET MVC Routing Overview
One of the options is Resharper - it more or less can determine where you use Html.ActionLink() or Html.BeginForm() that points to a controller action. But it won't detect any posts/redirects done from JS.
Also another thing you can do is use T4MVC to make the links from views statically typed, so you can search on references.
Text search through the solution can help, but not always good as you already discovered - how many references to string Index do you have in an average MVC project? So this will help with distinctive controller/action names, but not with common names.
Apart from that you are on your own. If you try doing something clever, like in JS concatenate strings to give you the right endpoint - you are in trouble.
Another option if you know the application fairly well. Put a breakpoint on the controller action and then run some tests of the application.
I'm building a web app using ASP.NET MVC 4, with data storage provided by T-SQL database via Entity Framework. I'm integrating audit logging as I go, and I'd like to provide a nice human-readable summary of the action, so that I can present a friendly logs view with clear statements like "User Bob logged in", "User Alice updated article 'Foo'", etc.
An audit record currently consists of:
GUID
timestamp
user ID
action category (controller name)
action (action method name)
IsError (boolean; true means either this is a record of an error, or this action did not complete successfully)
blob of serialised details
At the moment, my logging uses a custom attribute which implements IActionFIlter; the OnActionExecuting() method logs the attempted action (serialising things like URL, parameters etc to the detail blob) and the OnActionExecuted() method goes back and sets IsError to true if there are no errors, and appends either the returned result or exception with error message and stack trace etc to the details. I want to add another column for description strings, but I can't see a tidy way to do it.
The furthest I got was to pass a string to the attribute, something like "User $user logged in" and then have the log method scan the string for the $ character and replace that word with anything from the parameters dictionary whose key value matches that word (minus the $ character). This is a little limited; for example, if articles are stored by ID number, then the best you can manage is "User 18 edited article 37". There's no real way to get at the username or article title; you can't pass instance data to the attribute because it's baked in at compile time, and I don't really want my logging method to be making all sorts of database calls to get that sort of data, not least because it then becomes impossible (or at least a real pain) to have a single generic logging method.
The alternative to all this is to have a static audit logging class and call something like AuditRecord.WriteLog(foo); all over the place, perhaps with some kind of descriptor class I can use (or inherit from) to describe different types of action, storing all the parameters and generating a description string as needed, but seems less elegant to me; I really like being able to just tag [AuditLog] on top of a method and know that it'll be recorded.
I'd like to avoid huge amounts of conditional logic, like using the controller and action names in some big switch statement to select the correct string template. If I could just get hold of things like article titles in the logging method then it'd be fine. Is there a neat, simple way to do this?
We recently had a similar discussion at work regarding both logging audit history and applying more complex security rules across our new MVC project.
In the end the most "elegant" solution that we came up with was to have the method calls within the controller actions (Your alternative method).
For example:
[HttpPost]
public ActionResult CreateItem(Item item)
{
//Simplified
CheckSecurity(SecurityTypes.ItemCreation);
LogActivity("Created an item");
//Rest of action code
}
This gave us the flexibility to account for all possible use cases, and allowed us to wrap up the logic into simple to use methods to reduce code repetition.
It may be late to answer, but I think there is a good alternative to keep using action filter attributes and to be able to access per-request lifecycle objects.
As anaximander noted it above, the underlying problem is that attributes are resolved by the CLR, so their lifetime cannot be controlled and they don't mix very well with an IoC container (to make them transient, per request instance, etc.).
Usually, in .NET a new instance of attribute is created each time it is resolved by reflection (GetCustomAttribute method).
Furthermore, in the case of MVC/webapi, action filter attributes are cached, so they normally are created just once.
The conclusion is that attributes are designed to annotate only, in other word, they should contain only metadata (they are DTO). Unfortunately, my understanding is MVC and WebApi frameworks are not designed in this way. To restrict action filter attributes to simple DTOs and to be able to manage lifecycle of the logic part around them, special means must be taken.
I think your use case fits perfectly to the solution provided in a Steven van Deursen's great article. It demonstrates how to separate attributes data from logic and it is based on an action filter registered globally, the so called "dispatcher", with the ioc container as a dependency.
The container is not resolved statically. It is provided in the constructor of the global filter when it is registered at the application initialization.
So each time it is executed, it looks for any attribute marker on the action being executed and it resolves a generic interface where the attribute is the generic parameter. Instead of having an action filter attribute which merge data and behavior, you end up using two classes: a plain old attribute - the marker - and the corresponding implementation of the generic interface for its logic counterpart. The container is used to resolve the generic interface. If your filter depends on per-request components, you can create an implementation of the generic interface with the services you need. If it does not depend on other services but you need a per-request lifetime (to measure time between the beginning and the end of an action for example), it also does the job, thank to the use of the container to resolve the generic interface. The aforementioned article contains code examples for WebApi, MVC and ASP.NET 5.
Also, Mark Seemann has made an article on the same approach.
I think it does not provide a good solution for all cases, like authorizations filters and perhaps exception filters, but to me it is the most elegant way for many action filters.
The better way would be to format this data when you view it, rather than build these things during the logging process.
If the action is "login", and the recorded user is available (which you should do) then you build that message in the viewer.
So you log all the raw events, then build the "view model" or "read model" based on this data that is more descriptive. this can allow you to even re-parse all the raw data if you want to change it's description. You could log a lot of data that isn't used yet so you could implement it later within the description.
IMO, sprinkling methods this way inside actions doesn't seem like a good idea and an Action Filter on the controller or base controller is cleaner. if you wanted to do that you could use an AOP (aspect oriented programming) framework to avoid cross cutting...
So I am reading about building MVC3 projects and there is one thing that seriously bugs me. The folder structure of the project in no way corresponds to the path of the HTTP request. There is a bunch of things I like and would want to use, but having a flat folder structure is not one of them.
Why is this a problem? Well, I see it becoming a problem when building a site with a heavy mix of content pages and various forms/dynamic pages (most of our sites are like that), which would typically be done by different people. It seem it would be too complicated for client-side developers to follow routing rules of dynamic pages and/or creating new ones.
What I would like to understand is if there is way to configure MVC3 application in such a way that:
it follows directory structure for finding controllers without explicit route map for each one
views live in the same folder as corresponding controller
routing magic still works for actions and parameters
For instance I'd like to have a request /fus/ro/dah/ to try to find DahController in the \webroot\fus\ro\dah\ folder and execute its Index action. If not found it would look for RoController with Dah action in the \webroot\fus\ro\ folder, etc.
It is entirely possible that MVC was not meant to be working this way at all and I am just trying to force a square peg into a round hole.
UPDATE:
Looks like I can drop a view file into the desired folder structure, and it will be executed. However layout would not work apparently because it is expecting a controller. Does this mean I have to create a controller for pure content pages? That is a pretty crappy design...
UPDATE 2:
Main issue right now is that creating "fus" folder means that MVC will not even attempt to look for FusController... not under "fus" folder, nor anywhere else. Is it possible to get around that?
For instance I'd like to have a request /fus/ro/dah/ to try to find
DahController in the \webroot\fus\ro\dah\ folder and execute its Index
action. If not found it would look for RoController with Dah action in
the \webroot\fus\ro\ folder, etc.
MVC is not designed for a particular need like this, it is a general framework for building applications using model-view-controller pattern.
If you can't bend the application for the framework you can bend the framework for the application and honestly MVC is very customizable. [As a proof, in the current project (migration from ASP to MVC) that I'm working we have models as xml and no classes also we are using XSLTs for rendering. With a little work we have created custom components like custom view engine, custom validation provider, custom model binder... to make the framework best fit for the application and it does]
MVC is not designed and not forces to use it as it is and you can customize/extend as much you want. In your case you may have to create a
custom controller factory (because you want to customize the way in which the controller is seleced),
custom view engine (because you want to customize where the view is placed)
and may be others.
For custom controller factory you have to extend the DefaultControllerFactory class. There are lot of articles you can find through Google that explains about how to create custom controller factories.
Depending upon the view engine you are using you have to extend the respective one. For ex. if you are using web forms then you have to extend the WebFormsViewEngine and it razor then RazorViewEngine.
For more info. check this link
http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx
you can mixup Asp.net and Asp.net MVC. as LukLed said, MVC is convention over configuration pattern. if you follow the convention. you dont need to configure. you can check this link for mixing up the asp.net content with MVC3
Mixing Asp.net and Razor
I believe ASP.NET MVC is not meant to be used that way. While you can configure MVC to do it, it is better to keep standard /controller/action/parameters URL format. If you have complex website with many different functionalities, areas may be helpful http://msdn.microsoft.com/en-us/library/ee671793.aspx. Every area get its own set of controllers, models and views, so teams working on different parts of website won't disturb each other.
While it may sound convenient, that framework first searches for DahController and executes Index action, then searches for another one, I find it bad idea. URLs should be clearly defined and Fus controller with Ro action shouldn't just stop working, because someone created RoController with Index action.
Look into using Areas as well. I think that helped me get over my folder structure issues with MVC honestly. So i could use the base folder as my Home details, then i could have a 'Admin' area which was a separate folder, things like that.
How "regular ASP.net" do you want it to be? If you want to do "legacy" ASP.Net Web Forms mixed in with MVC, you certainly can - re: mixing MVC with "file based aspx" - aka "hybrid". At the end of the day, it's all ASP.Net.
This is a standard MVC Application generated by Visual Studio. I've added a folder somedirectory where I want to use the legacy folder/file.ext paradigm and have a default.aspx Web Forms file:
Can I navigate to it via http://foo.com/somedirectory? Yes.
Can I use "pretty urls" too? Yes
Vanilla Global.asax generated by VS, just added MapPageRoute:
....
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//using "pretty urls" - ordering your routes matter.
routes.MapPageRoute("theWebForm", "legacy", "~/somedirectory/default.aspx");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
so now I can navigate to it via http://foo.com/legacy
Just check the order of your routes, and perhaps plan on your naming conventions so you don't have "collisions"...
Hth....
I'm in the process of trying out a few things with MVC whilst designing a system and wanted to try and see if I could use the concept of Controllers outside of the MVC framework. When I say outside, I mean within my own C# service as opposed to a web-site.
I started a simple console application to test the theory and it was simple enough to change the profile to a non-client profile, add in System.Web.Mvc, create a controller and have it return a JsonResult. The ease of which this got set up pleased me as that is half the work done if I want a service to respond with JSON.
The next step is to set up a Http Server class, and I would love it if I could leverage the other part of the framework which will map incoming requests to my controllers. Unfortunately, this is the part where I am lost and I have no idea what code goes on behind to arrive at a particular controller's function with the parameters all in place.
Has anyone got an idea on how to accomplish this, or a resource to look at?
In short: I'd like to leverage the use of Controllers in my own service, running it's own HTTP Server.
You can use the design pattern without using the framework - what I mean is, you can apply the model view controller pattern wherever you believe it solves the problem - if you think that you can replace "view" with "service", you could apply some of the concepts...
http://msdn.microsoft.com/en-us/library/ff649643.aspx
However, there are other patterns that may lend themselves better to services, although if we are talking specifically about a JSON service, then just using the ASP.NET MVC framework as it is would work well (rather than trying to re-write it).
Are you not trying to reinvent the wheel?
If returning JSON is one of your main purpose then WCF fulfills your need. Having WCF with you you are free to host it in IIS. This serves your second purpose having its own HTTP server.
You are trying to achieve some kind of routing where based on URL your different actions will be called. Isn't it similar to having a WCF service with different methods and client is calling each of them with different URL?
Trying controller concept in a non web application seems to be innovative, however in your case it looks like over-engineering.
The basic MVC pattern isn't all the difficult to replicate. I would seriously consider writing your own, rather than trying to shoehorn the MVC classes into your app.
Simon
If it helps you, the entire ASP.Net MVC Framework is open source, you can download it all from http://aspnet.codeplex.com/ . You can use the libraries here to view how the Framework is doing things behind the scenes and adapt things for your own use as appropriate.