Conditional namespaces in mvc views - asp.net-mvc

I'm working on MVC 3 and using resource files to localize the application. Now we have another customer on board for the application and they would like to change some of the text on the application..typical.
I have create a separated resource file for them and would like to do something like this in views
if (customer =A )
#using Resources.customerA
else
#using Resources.customerB
I've a resource class in both namespaces so something like this works fine if I change the namespace
Resource.WelcomeUser
Is it possible to use conditional using statement in views? I'm unable to find the right syntax for this. Any ideas?

You can put both using statements in View, but when you use classes you would have to write some namespace prefix.
Example:
#using Project.Resources.customerA
#using Project.Resources.customerB
using classes:
customerA.WelcomeUser
customerB.WelcomeUser
I think there is no other way, because two files cannot have the same path.

What you're really talking about is the provider pattern. You have two (or more) interchangeable things, and you want to be able to use one or the other contextually.
The correct way to do this in an OO context is to create and use an interface, while then injecting the actual implementation you want at runtime. You can actually achieve this in ASP.NET Core, which supports injection in Views, but in ASP.NET MVC 5 and previous, you'd need to go a little out of your way. I'm imagining these are currently static classes, since you're referencing them merely via namespace. With that approach, you'd need to follow #Ssheverdin's advice and use the FQN of the class (i.e. with the namespace):
#if (customer == A)
{
#Resources.customerA.StaticClass.Property
}
else
{
#Resources.customerB.StaticClass.Property
}
Alternatively, you could change the static classes to be instance classes and use a factory pattern to return the right one. This is a very simplistic example, but hopefully enough to convey the idea:
public static class ResourceFactory
{
public static IResourceClass GetForCustomer(string customer)
{
switch (customer)
{
case "A":
return new Resources.customerA.ResourceClass();
default:
return new Resources.customerB.ResourceClass();
}
}
Then:
#{ var resource = ResourceFactory.GetForCustomer(customer); }

I have managed to achieve the behaviour by adding a web.config file under views folder and including the namespaces there, i have to remove the #using statement from all views obviously. You might find that intellisense doesn't work anymore for you so try closing all views and reopen them again.
With this way I can create a separate web.config file for each customer and specify the relevant namespaces accordingly. Now just have to make sure to provide the RIGHT config file for each customer when deploying the release:)

Related

Common functionality across multiple ASP.NET MVC controllers

I'm working on ASP.NET MVC application & have a quick design question for you.
So I need to implement a common functionality for all my controllers (well, most of them).
I don't want to repeat the same logic in all the controllers.
What'd be the ideal approach in the best interest of MVC?
I found people saying create base controller and inherit it in your controllers. But when I visualize a controller, I can see it'd contain only action methods that return some content/views - Correct me if I'm wrong.
OneController
{
ActionMethod A1
{
//Code to return list of objects for the given integer value. So it calls database stored procedure.
}
}
...multiple such controllers are there.
I'd still like to have A1 exists in the OneController, just put its logic somewhere common place.
Also some people suggest to create just plain Helper class to place the common method.
Could you please suggest me what approach will be better (Or any other appropriate approach)? Thanks.
I agree with you that, most of the times, it only makes sense to inherit from base controllers when we're talking about Actions or methods that are really related. But of course, you can just use base controllers for everything. Your choice.
Other than that, you have 2 options. For classes that have little to no chance of being polymorphic (change behavior depending on the implementation), you are fine to create static classes and just use them inside your controllers. An example would be a class that does math calculations, these are not that polymorphic by nature.
For all the other cases, I'd strongly suggest that you use dependency injection. One of the reasons being that unit testing will become way easier. Here's a guide on how to do it for MVC 4 onwards using the built in engine: https://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection. If you don't want to use it and use Ninject or Simple Injector, you can implement your own ControllerActivator and use Ninject, for instance, to get an instance of your controller.
When using dependency injector, normally your controller would get the dependencies in the constructor, like this:
public class StoreController : Controller
{
private IStoreService service;
public StoreController(IStoreService service)
{
// service in an injected dependency
this.service = service;
}
}
For more information, Google ASP.NET dependency injection.

Is it legal to extend an entity model with functionality in ASP.NET MVC

first of all here is my situation. I am programming an intranet application using ASP.NET MVC 3 with Entity Framework 4.1. My application has been developed using the "Unit of Work" and "Repository" design patterns.
How ever in my opinion it should go the way that my application has an unit of work that provides a central access to all the repositories which further provide access to the entities.
Lets say I have a entity called "ProductApprovalDocument" with the properties "id", "creationDate" and "approvalDecission" stored in the database. Now I want the user to be able to access a PDF file of the document thats shortly described by the entity. Because the files are stored in a central directory on a file server using the URL format "[fileServerDirectoryPath]/[ProductApprovalDocument.id].pdf", I do not want to save an extra property for that filepath on the database. What I would like to do, is give the entity an extra property called "filepath" that automatically constructs the path with the given information and returns it.
Now the Problem:
I use an interface called FileService to abstract file access from the rest of the application. Now in my case I would have to access the UnitOfWork object out of the entity model, to retrieve the current FileService implementetion and get the preconfigured filepath. I think that's the totaly wrong way because to me an entity model should only be used as a data container not more or less.
Now the Question:
How do I handle such a situation. I would not like to always set the filepath property through the controller because ist more or less static and therefore could be done somehow automatic by the model.
Edit (final solution):
Thanks to the answer of Andre Loker I gained another point of view to my problem.
What was the central target I wanted to reach?
I wanted the user to gain access to a file stored on a fileserver.
Do I have to provide every displayed entity with the total filepath?
No! Think about the principle of MVC! User actions get processed by the controller just in time. You don't have to provide information untill it really get's used.
So the solution is just to render all data as usual but instead of displaying a static html link to the files, you have to include an ActionLink to the Controller which calculates the filepath on the fly and automatically redirects the user to the file.
In the View do this:
#Html.ActionLink(Model.ID.ToString(), "ShowProductApprovalDocumentFile", "ProductApprovalDocument", new { ProductApprovalDocumentID = Model.ID }, null)
instead of this:
#Model.ID
And add an corresponding Action to the controller:
public ActionResult ShowProductApprovalDocumentFile(int ProductApprovalDocumentID )
{
return Redirect(_unitOfWork.FileService.GetFilePathForProductApprovalDocument(ProductApprovalDocumentID));
}
Thanks to the guys that took the time to give me an answer and special thanks to Andre who lead me to the satisfying answer! :)
If I understand the property correctly, there are several options:
1) Make the FilePath property use a service locator to find the FileService:
public string FilePath {
get {
FileService fileService = DependencyResolver.Current.GetService<FileService>();
return fileService.GetFilePathForDocument(this);
}
}
While I'm not a hugh fan of static service locators as they make testing more difficult, this could be a viable option. To make it more easily testable you can make the file service locator injectable:
private static readonly Func<FileService> defaultFileServiceLocator = ()=>DependencyResolver.Current.GetService<FileService>():
private Func<FileService> fileServiceLocator = defaultFileServiceLocator;
public Func<FileService> FileServiceLocator {
get { return fileServiceLocator; }
set { fileServiceLocator = value ?? defaultFileServiceLocator; }
}
And then use this in FilePath
public string FilePath {
get {
FileService fileService = fileServiceLocator();
return fileService.GetFilePathForDocument(this);
}
}
This way you can inject your own file service locator during testing.
2) Explicitly require the FileService when retrieving the file path. Instead of a FilePath property you'd have:
public string GetFilePath(FileService service){
service.GetFilePathForDocument(this);
}
The problem with this is of course that now the caller of GetFilePath needs to have a FileService. This isn't much of a problem for controllers, because if you use an IoC you can inject a FileService into the controller constructor. This approach is the cleaner one as it doesn't depend on service locators, but as you see it is slightly more inconvenient for the caller.
3) Inject the FileService into the document class itself.
Instead of using a file service locator you'd inject the file service itself when you construct your ProductApprovalDocument. With this approach you can use a simple FilePath property again. The main problem is that this often doesn't play too well with ORMs, as they often construct the objects using a default constructor and you'd have to somehow hook into the object construction process to inject the dependencies. Also, I'm not a big fan of injection services into domain objects.
4) You set the FilePath from outside the entity. As you said this should be done somewhat automatically as you don't want to do it manually every time. This would require some layer through which all entities need to pass which sets up the FilePath property.
5) Don't make FilePath a property of ProductApprovalDocument at all. This would be a reasonable choice, too. ProductApprovalDocument doesn't know anything about its FilePath, so why should it be a property? Its the FileService that calculates the value. You can still have a distinct view model version of ProductApprovalDocument which does have a FilePath property. You'd set the property when you create your view model:
var model = new ProductApprovalDocumentViewModel();
mapper.Map(realDocument, model); // map common properties with AutoMapper or so
model.FilePath = fileService.GetFilePathForDocument(realDocument);
However, if ProductApprovalDocument needs to do something with its FilePath (why would it?) this approach doesn't work anymore.
Personally I'd go with solution 5, 2 or 1 in that order of precedence, where applicable.
Whilst I would be hesitant to rely on being able to calculate the filepath and I would prefer to store it as part of the entity (in case it ever needs to change for some reason), in your situation if I was adamant I wanted to do it the way you've said, I think I would extend the FileService/ViewModel to have a Filepath property which was derived in the fashion you have stated.
e.g. if I wanted to create a download link I'd do this in the ViewModel
public string FilePath
{
get
{
return String.Format(#"thehardcodedbit{0}.pdf",ID);
}
}
EDIT: If you have an Entity generated by EF4.x then it will have been generated as a partial class so you could always extend it like this (I have done this sort of thing and it works okay):
Say the generated entity looks like this:
Namespace Da_Wolf.Model.Entities.File
{
public partial class UploadedFile
{....}
}
Then you could create a partial class like this:
Namespace Da_Wolf.Model.Entities.File
{
public partial class UploadedFile
{
public string FilePath
{
get
{
return String.Format(#"thehardcodedbit{0}.pdf",ID);
}
}
}
}
Now you have the property you desire available everywhere without adding anything to the ViewModels.

For specific controller make Windsor instantiate different classes

I use S#arp Architecture which uses Windsor Castle for IoC. I got a new controller now that, unlike all other controllers in the project, need a different implementation of the same interfaces. I.e. all controllers use ProductsRepository: IProductsRepository as implementation, but the new one has to use SpecificProductsRepository.
How do I configure it to recognize and manage this automatically? Either in pure Windsor way, or with ASP.NET MVC help (e.g. in my custom controllers factory).
OK looks like I need subcontainers. Still searching.
An easier and much simpler way would be to use Windsor's service overrides.
E.g. register your repos like so:
container.Register(Component.For<IProductsRepository>
.ImplementedBy<ProductsRepository>()
.Named("defaultProductsRepository"),
Component.For<IProductsRepository>
.ImplementedBy<SpecificProductsRepository>()
.Named("specificProductsRepository"));
which will ensure that the default implementation is ProductsRepository. Now, for your specific controller, add a service override like so:
container.Register(Component.For<NewController>()
.ServiceOverrides(ServiceOverride
.ForKey("productsRepository")
.Eq("specificProductsRepository"));
You can read the docs here.
Edit: If you want to register your repositories with AllTypes, you can adjust the registration key e.g. like so:
container.Register(AllTypes.[how you used to].Configure(c => c.Named(GetKey(c)));
where GetKey e.g. could be something like:
public string GetKey(ComponentRegistration registration)
{
return registration.Implementation.Name;
}
OK, these days I tend to answer my own questions... so here it is for those who need it.
// create subcontainer with specific implementation
var mycontainer = new WindsorContainer();
mycontainer.Register(AllTypes.Pick()
.FromAssemblyNamed("My.Data")
.WithService.FirstInterface()
.Where(x => x.Namespace == "My.Data.Custom")
.Configure(x => x.LifeStyle.Is(LifestyleType.PerWebRequest)));
container.AddChildContainer(mycontainer);
ControllerBuilder.Current.SetControllerFactory(new ExtendedControllerFactory(
new Dictionary<string, IWindsorContainer> { {"", container}, {"Lm", mycontainer} }));
The controller factory chooses appropriate container based on name. The biggest challenge there is to call appropriate container's Release(controller) at the end of request, i.e. remember which container was used to instantiate controller. But this can be solved in several ways I suppose - remember in thread-specific (in HttpContext), remember in BaseController property, remember in internal dictionary, etc.

Does ASP.NET MVC Has Anything Equivalent To WPF's DataTemplate Feature?

In my ASP.NET MVC project, I have a polymorphic collection that I wish to render - say, an IEnumerable<ISomething> where the individual items may be a mix of different implementations of ISomething.
I'd like that list rendered, where each concrete type renders according to its own template (perhaps a strongly typed ViewUserControl).
In WPF, I'd be able to specify DataTemplates that would automatically bind concrete types to specific templates. Can I do something similar in ASP.NET MVC?
Obviously, I can iterate through the list and attempt a cast using the is keyword and then use a lot of if statements to render the desired control, but I was hoping for something more elegant (like WPF).
I ended up with developing a solution myself - I have described it in DataTemplating In ASP.NET MVC.
I'm not sure if I get you fully, but, why don't you implement a method to your ISomething interface like render for example, which by contract will be implemented to all of your other concrete entities, and then iterate through each item in the polymorphic collection and call it.
I had a similar issue and never found a "simple" answer. I had the benefit of knowing that all items in the list would render the same way so I created a decorator for ISomething, converted the list to IEnumerable using some code from the Umbrella project (http://umbrella.codeplex.com), and then extracted out the relevant pieces. Kinda like the following:
public interface ISomethingDecorator
{
string Description { get; }
string[] Actions { get; }
}
public class BigSomethingDecorator : ISomethingDecorator { /* ... */ }
public class SmallSomethingDecorator : ISomethingDecorator { /* ... */ }
Then, as I said, I use the Umbrella project to convert from ISomething to ISomethingDecorator and returned IEnumerable to the View.
Don't know if it'll help you with what you're trying to do -- especially being a month late -- but I thought I'd let you know how I handled it. If you're displaying completely different formats, it probably won't do the trick but maybe it can get you a starting point.

Language dependent routes in ASP.NET MVC

Has anyone had any experienced with making language dependent routes with ASP.NET MVC? What I would like to do is have localized url's to improve SEO. So for example http://mysite.com/products/cars would map to the same controller/action as http://mysite.com/produkter/bilar?
I have tried browsing around a bit, but I could not find anything similar to this. I'm not even convinced it is really such a good idea, but I would imagine that it would help SEO when users are doing searches in their own language. I would imagine this would take some customization of the mvc route engine.
Edit: Mato definitely has the best solution so far, I would like to see a Custom RouteHandler solution though for reference.
You could implement an own controller factory class which translates the controller name before initializing it. You could for example store the translations in a resource file or in a DB. The easiest way to do this is to inherit from DefaultControllerFactory and to overwrite the CreateController function.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace System.Web.Mvc
{
class CustomControllerFactory : DefaultControllerFactory
{
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
/**
* here comes your code for translating the controller name
**/
return base.CreateController(requestContext, controllerName);
}
}
}
The last step would be to register your controller factory implementation when the application starts (in the Global.asax).
namespace MyApplication
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
}
}
}
One thing with SEO is, if a search engine finds two identical documents on two different links, it may reduce page rank for one of the pages. You need then to translate the page content as well.
You could use regular expression routes (http://iridescence.no/post/Defining-Routes-using-Regular-Expressions-in-ASPNET-MVC.aspx), and then do something like
routes.Add(new RegexRoute(#"^(Products|Produkter)$", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Products" })
});
I won't recommend a Regex based approach because it will be error-prone, other than requiring a strong level of manual customization of all the available URL patterns (wich can be a real pain for non-trivial websites).
Just as #Runeborg said, I strongly recommend a more automated way of doing the job. For MVC 5 (and <) web applications I always use the following one, which I found to be the most versatile one among those I've tried in the latest years.
You basically need to implement three things:
A multi-language aware route to handle incoming URLs (if you're using MVC5 or above you could also go for Attribute-based routing instead, but I still prefer to use a global rule to handle this).
A LocalizationAttribute to handle these kinds of multi-language requests.
An helper method to generate these URLs within your application (Html.ActionLink and/or Url.Action extension methods).
See this answer for further details and code samples.
For additional info and further samples on this topic you can also read this blog post that I wrote on this topic.

Resources