I'm using ASP.NET MVC2 RC and I have built security on top of the Areas/Controller/Action specification, using basically a table that tells the infrastructure which role has permission to execute which controller action.
The code I used to get the "area" was this
RouteData.Values["area"]
And then I checked that in the Database. My problem is that when I migrated from MVC 1 RTM to MVC2 RC, the area goes in the DataTokens collection, and if the controller that is being called is in the root area, the following code returns null
RouteData.DataTokens["area"]
Do you know if there's any way to tell MVC that if "area" is not in the DataTokens collection, it should have string.Empty?
I'm trying to avoid modifying my code to check that for null.
Thanks!
As a work around, you can manually add the value from RouteData.Values to RouteData.DataTokens. But ideally you need to address the root cause.
Here's the work around for the issue:
if (controllerContext.RouteData.Values.ContainsKey("area"))
{
ControllerContext.RouteData.DataTokens.Add("area", ControllerContext.RouteData.Values["area"]);
}
Why not simply check if RouteData.DataTokens["area"] is null (or empty) and assume the default area when it is?
Edit
Apologies, I didn't read the the last line of your question before answering. What's the issue with modifying the code?
Related
I'm new to Sitecore MVC and currently with web forms I have all the sites organized under:
\Website\Sites\Site1\css|js|Layouts|Sublayouts|etc.
\Website\Sites\Site{n}\css|js|Layouts|Sublayouts|etc.
I'm able to add an MVC site to my solution and works fine alongside the web forms sites; however, adding a second MVC site that happen to have the same controller/view names generates a conflict.
For example, if I create a controller for Site1
Controllers/Site1/FooController (has index and hello)
Then the views are:
Views/Foo/Index
Views/Foo/Hello
But if Site2 also has a controller with the same name then it's a conflict:
Controllers/Site2/FooController (has index and hello)
Then the views are:
Views/Foo/Index
Views/Foo/Hello
But they're used by Site1.
The question is how to setup two (or more) MVC sites that happen to have the same controller/view names. Is there a recommended way to structure the sites in the solution or do I have to override pipelines/processors?
Thanks
Update:
Thanks everyone. Areas solved my problem but introduced two new problems:
The conflict in the controller names which solved by putting the namespace, class and dll names in the controller name in Sitecore - reference: http://blog.xcentium.com/2014/03/sitecore-mvc-and-duplicate-controller-names/
When the controller returns a view, I have to put the full path of the view; otherwise, I get an error where the view is not found.
For example: return View("~/Areas/Site1/Views/Home/Index.cshtml");
I'm looking into a fix provided from a developer from Sitecore's forum:
http://www.chrisvandesteeg.nl/2014/06/13/sitecore-mvc-in-a-multisite-environment-areas/
I'll try it out and report back.
you need to use namespaces in routes.MapRoute, look at the below posts which have already discussed:
Is it possible, in MVC3, to have the same controller name in different areas?
Multiple MVC projects in a single solution
and below is the post by John west post which relates your situation:
http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2012/06/Using-Web-Forms-and-MVC-in-a-Single-Solution-with-the-Sitecore-ASPNET-CMS.aspx
We had the similar problem and answer was to separate out every site with MVC areas and they works perfectly. Though we ran into issue of controller name duplication but that can be resolved by adding the namespace during the area route registration.
But a clean way to implement this is to let Sitecore know about the MVC areas and initialize your controller/action with area and namespace. This process has been blogged by Kevin and he has a package as well. It expect you to define the area name in controller rendering.
http://webcmd.wordpress.com/2013/01/24/sitecore-mvc-area-controller-rendering-type/
To avoid the hard coded path of view(s) you can always extend controller rendering template to add view path and create an action filter to add the view path after action is executed. Add the below code in action filter and register the filter in sitecore action filter registration pipeline.
public void OnActionExecuted(ActionExecutedContext filterContext)
{
ViewResult result= filterContext.Result as ViewResult;
if(result == null) return;
Rendering redering = RenderingContext.CurrentOrNull.With(x=>x.Rendering).Return(x=>x,null);
string viewName= rendering.Return(r=> r.GetFieldValue(CustomMvcSettings.ViewPathField), string.Empty);
if(String.IsnullOrEmpty(viewName)) return;
result.ViewName = viewName;
}
The best thing you can do is split your websites up in different projects in the same solution.
Building two websites in the same project can become unstructured and messy.
After that you can route the controllers with the same name using the different namespaces.
Sitecore mvc duplicate controller
Just to keep this topic in sync with the SDN forum,
I recommend using a sitecore specific constraint, as described at
http://www.chrisvandesteeg.nl/2014/06/13/sitecore-mvc-in-a-multisite-environment-areas/
This solution allows you to set the attribute mvcArea on your configuration node
I'm sure the question is as stupid as simple, but since nobody can give me a hint, I give it a try: I'm learning MVC Asp.Net by creating a small company-internal application, which has only 1 Page.
I worked trough the Tutorial: http://www.asp.net/mvc/tutorials/mvc-5/introduction/getting-started, which helps me a lot.
My problem itself: I went to the Controllers-Folder, added a Controller by selecting "MVC 5 Controller with read/write actions", then in the Views-Subfolder Views\NewItem\ I added a Index.cshtml by selecting "Empty Page".
But now when I debug the Program and select in the URL it keeps shooting a 404-error, meaning the Page is not found. I debugged the Controller, but it doesn't even goes to the Index-Method.
Is there anything I'm missing. I guess it's so stupid and clear I dont even find it on the Internet.
Nevertheless thanks in advance for all answers.
I think the easy way to add a View for your action method that is placed inside the controller you're working at, is to right click inside the body of your action method (that you want the users to access from the browser) and add the View you want, and the MVC automatically will add the View in the right place inside the View folder in Solution Explorer.
Please check you RouteConfig for rout configuration
Ensure that your controller is correctly named - e.g. NewItemController. If it doesn't have the Controller suffix, it won't be picked up.
It should also have an action method matching your view name, e.g. public ActionResult Index() in this case.
In my /Views/Shared/ folder I created an EntityNotFound.cshtml razor view. In one of my controller actions I have the following call:
return View(MVC.Shared.Views.EntityNotFound, "Company");
This causes the following exception:
System.InvalidOperationException: The view '~/Views/Shared/EntityNotFound.cshtml' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Company/Company.cshtml
~/Views/Company/Company.vbhtml
~/Views/Shared/Company.cshtml
~/Views/Shared/Company.vbhtml
I am confused, because it does not even seem to be attempting to search ~/Views/Shared/EntityNotFound.cshtml. Even if I replace MVC.Shared.Views.EntityNotFound with "EntityNotFound" I get the same error.
Why is Asp.Net MVC not even attempting to find my shared view?
Have a look at the list of overloads for View();
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.view.aspx
Specifically, when you pass View(string,string); it sees the second string as the name of the master view.
Whats probably happening, is that it can't find the "Company" master view, you'll not the exception messages says
... or its master was not found...
Which means that it is probably finding the NotFoundException.cshtml, but can't correctly find the Company.cshtml that it's looking for as the master.
The correct syntax should be this (don't pass path, MVC is a language by conventions)
return View("EntityNotFound");
Assuming "Company" is a param you wnat to pass to the view, try like this:
ViewBag.ErrorEntity = "Company";
return View("EntityNotFound");
And from the View
<p>Entity not found: #ViewBag.ErrorEntity</p>
I've been using enity framework that came with 3.5sp. And now I've redone things for enityframework 4 and asp.net mvc 2. I've come across something (which worked in my previous version and asp.net mvc 1.0).
I have this:
public IQueryable<Booking> GetBookings()
{
return from b in _entities.Bookings.Include("BookingObject")
select b;
}
And in my controller I have:
return View("Index", new BookingsViewModel
{
Bookings = _br.GetBookings().ByDay(DateTime.Today)
});
And it doesnt seem to include the "BookingObject"-entity, so I can type like <%= Model.Bookings.BookingObject.BookingObjectName %> in my view.
What might be missing here? Do I need to turn something on in the diagram for it to include entities or?
/M
No, it should work exactly as before. I'm assuming you have a navigation property BookingObject on your Booking item - but then the .Include() would error out if you didn't. I don't think there's anything else you need to set up, or at least not that isn't done by default. I'd verify the definition of the navigation property in the .edmx editor at least.
You're definitely using the final RTM EF4 code? We hit a bug in the final RC building incorrect SQL and returning no results for one specific include sequence, but it was a lot more complex than that.
Failing that I would use SQL Server Profiler to trace out the SQL it's using and try and debug that.
I've been trying to use CookieTempDataProvider to pass a basic message between a post (entity update) and a get (entity list) using the RedirectToAction method. When using the default TempData implementation this works fine, however when I use the cookie-based version from the MVC Futures project, the TempData dictionary is empty after the redirect. This is because the TempDataDictionary is returned as null from the DeserializeTempData method. I know exactly what line of code the problem occurs on, and I know how to fix it, but I can't believe that I'm the only one to have this problem.
Maybe I'm using the wrong version of the MVC Futures project, but I've just downloaded the ASP.NET MVC v1.0 source and the problem definitely exists there. Does anyone else use CookieTempDataProvider, and does it work for you?
The problem with the CookieTempDataProvider class, as I see it, is on line 62, where it is casting the deserialized object as TempDataDictionary instead of as IDictionary<string, object>. When I make this change, everything works perfectly.
Anyone else see this problem, or is it just me?
Same here. Didn't work after using assembly as is from MVC Futures. Changing line 62 as you suggested fixed the problem. Thanks for posting.