I'm developing an multilingual enterprise web site and I would like to store the localization in database.
I have read the following article which is very good but I personally think that is a an overhead and I can achieve the same much easy:
Extending the ASP.NET 2.0 Resource-Provider Model
I have already setup some ground but I'm not sure if my approach is fine. Basically I have created a service that is registers with DI.
public interface ILocalizedStringProvider
{
string GetLocalizedString(string key);
string GetLocalizedString(string key, string deafultValue);
}
Also i have created a Html helper like this
public static MvcHtmlString LocalizedString(this HtmlHelper helper, string key, string defaultValue)
{
if (string.IsNullOrEmpty(defaultValue)) return new MvcHtmlString("");
if (string.IsNullOrEmpty(key)) return new MvcHtmlString(defaultValue);
ILocalizedStringProvider localizedStringProvider = DependencyResolver.Current.GetService<ILocalizedStringProvider>();
if (localizedStringProvider == null)
{
return MvcHtmlString.Create(defaultValue);
}
string val = localizedStringProvider.GetLocalizedString(key, defaultValue);
if (string.IsNullOrEmpty(val))
{
return MvcHtmlString.Create(defaultValue);
}
return MvcHtmlString.Create(val);
}
Then the helper is simply invoked from the view.
First I want to know if this approach is good and if is not an anti-pattern.
Second my concern is this line:
ILocalizedStringProvider localizedStringProvider = DependencyResolver.Current.GetService<ILocalizedStringProvider>();
Is it maybe better to resolve the service ILocalizedStringProvider in the controller with constructor injection and let the controller populate the ViewBag with the localization's?
Thanks!
You can use my Griffin.MvcContrib project. It contains a ready to use MS SqlServer implementation for storing localization in the database.
Introduction: http://www.codeproject.com/Articles/352583/Localization-in-ASP-NET-MVC-with-Griffin-MvcContri
Administration
There is also an adminstration area which you can use to manage the localizations:
SQL Server setup
https://github.com/jgauffin/griffin.mvccontrib/wiki/SqlServer
Source code
The project is available at github: https://github.com/jgauffin/griffin.mvccontrib
Here is a very good one :
http://west-wind.com/westwind.globalization/
It offers :
DB storage
Resx Import/Export
Strong Type Class generation
it is rapidly added to your projects via Nuget, and you have the Full Source Code.. Awesome stuff
Related
I'm developing an mvc application just to practice some best practices (trying to do everything the 'correct' way). To be more precise, I thought of building an MVC Application with some ajax endpoints for a chat service.
I wanted to have that one a little more flexible, so I thought of using interfaces to define the structure of used objects. Those interfaces should then be implemented by the DataLayer Project.
Now I wanted to define those interfaces in the Mvc-Project and put the datalayer stuff in a separate project. This would lead to a circular reference though, which I thought of as bad practice.
What is the 'correct' way to solve this issue? Is my approach reasonable?
Some code to show what I want to archive:
Mvc Project:
public interface IChatUser
{
Guid UserID { get; }
string Name { get; }
}
Datalayer Project (part of class):
public class User : IChatUser
{
private Guid _userID;
public Guid UserID
{
get
{
return _userID;
}
}
public string Name
{
get
{
return this.LastName + " ," + this.FirstName;
}
}
}
Is there a reason you aren't just using NHibernate? If you are then your controllers just have access to a Session object for any basic queries you want to run.
Complex stuff gets broken out into separate query or command objects.
We built a full MVC app using the stuff discussed here: http://ayende.com/blog/154081/limit-your-abstractions-you-only-get-six-to-a-dozen-in-the-entire-app and were very happy with the results.
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.
I am working on an ASP MVC 3 app and I'm writing a custom html helper. It's nothing special or hugely complex, but it will need an instance of an interface from structure map. I know I can simply call into structuremaps' object factory from inside the method, but since the rest of the app uses IoC rather than service location I'd like to keep it that way.
Is there a way to inject interfaces into extension methods from inside and asp net mvc app?
UPDATE
An example of what I'm doing might help:
public static class ShowUrl
{
public static string ForShow(this UrlHelper url, int showId)
{
var service = ObjectFactory.GetInstance<IPerformanceService>();
var showName = service.GetPerformanceTitle(showId);
return url.Action(MVC.Performance.Details(showId, showName.ToFriendlyUrl()));
}
}
Which is used like this:
<a href='<%= Url.ForShow(1)%>'>
Essentially I am trying to build a URL with a slug from an entity id. Maybe I'm just going about this in a really daft way.
I would not recommend doing this. Extension methods are generally best used for simple, well-known operations directly on a type. If your extension method is dependent on having an instance of another type, it is likely that it shouldn't be an extension method to begin with.
Consider making an actual service class that performs this functionality, and injecting it where it's needed. If you really need this in an extension method, consider wrapping the functionality your extension method requires in another static class/method, and avoid using any kind of injection or location.
Sharing some code might shed more light on your specific situation.
There is no way to inject dependencies into an extension method.
For ASP.NET MVC helpers, you are going to have to do some sort of service location - whether you bury that with some sort of abstraction is up to you.
You should NOT be calling structuremap directly in your extension method. Also, you should create a testable version that takes an IPerformanceService argument like below:
public static class ShowUrl
{
public static string ForShow(this UrlHelper url, int showId)
{
//Use the MVC DependencyResolver NOT Structuremap directly (DependencyResolver is using structuremap)
return url.ForShow(showId, DependencyResolver.Current.GetService<IPerformanceService>())
}
//For Unit Testing
public static string ForShow(this UrlHelper url, int showId, IPerformanceService performanceService)
{
var showName = performanceService.GetPerformanceTitle(showId);
return url.Action(MVC.Performance.Details(showId, showName.ToFriendlyUrl()));
}
}
Now you can pass in a concrete implementation of IPerformanceService in your unit test method.
Assert.Equal("TheUrl", url.ForShow(8, new PerformanceService());
More info on mocking UrlHelper: ASP.NET MVC: Unit testing controllers that use UrlHelper
I am trying to read an XSLT file from disk in my ASP.Net MVC controller. What I am doing is the following:
string filepath = HttpContext.Request.PhysicalApplicationPath;
filepath += "/Content/Xsl/pubmed.xslt";
string xsl = System.IO.File.ReadAllText(filepath);
However, half way down this thread on forums.asp.net there is the following quote
HttpContext.Current is evil and if you
use it anywhere in your mvc app you
are doing something wrong because you
do not need it.
Whilst I am not using Current, I am wondering what is the best way to determine the absolute physical path of a file in MVC? For some reason (I don't know why!) HttpContext doesn't feel right for me.
Is there a better (or recommended/best practice) way of reading files from disk in ASP.Net MVC?
string filePath = Server.MapPath(Url.Content("~/Content/Xsl/"));
I disagree with the idea that HttpContext.Current is "evil." It's not the hammer for every problem, but it is certainly better than, e.g., Session for stuff that it can do OK.
If you're using WebApi or not specifically within a controller class, you can use the following as an alternative:
HostingEnvironment.MapPath("/Content/Xsl/pubmed.xslt")
I would have the site root path injected into the controller constructor by the DI framework:
public class HomeController: Controller
{
private readonly string _siteRoot;
public HomeController(string siteRoot)
{
_siteRoot = siteRoot;
}
public ActionResult Index()
{
string filePath = Path.Combine(_siteRoot, #"Content\Xsl\pubmed.xslt");
return File(filePath, "text/xml");
}
}
As far as the site root path is concerned it can be expressed with the HostingEnvironment.ApplicationPhysicalPath static property.
I need to make a web application and I want to use MVC. However, my Model can't be one of the standard Models -- the data is not stored in a database but instead in an external application accessible only via a API. Since this is the first MVC application I've implemented I'm relying on examples to understand how to go about it. I can't find any examples of a non-DB based Model. An example of a custom Model would be fine too. Can anyone point me to such a beast? Maybe MVC is just to new and none exist.
It seems like I might be able to get away with the DataSet Model, however I've not seen any examples of how to use this object. I expect an example of DataSet could help me also. (Maybe it is the same thing?)
Please note: I've seen countless examples of custom bindings. This is NOT what I want. I need an example of a custom Model which is not tied to a specific database/table.
UPDATE
I found a good example from MS located here:
http://msdn.microsoft.com/en-us/library/dd405231.aspx
While this is the "answer" to my question, I don't really like it because it ties me to MS's view of the world. #Aaronaught, #jeroenh, and #tvanfosson give much better answers from a meta perspective of moving my understanding (and yours?) forward with respect to using MVC.
I'm giving the check to #Aaronaught because he actually has example code (which I asked for.) Thanks all and feel free to add even better answers if you have one.
In most cases it shouldn't matter what the backing source is for the actual application data; the model should be exactly the same. In fact, one of the main reasons for using something like a repository is so that you can easily change the underlying storage.
For example, I have an MVC app that uses a lot of web services - rarely does it have access to a local database, except for simple things like authentication and user profiles. A typical model class might look like this:
[DataContract(Namespace = "http://services.acme.com")]
public class Customer
{
[DataMember(Name = "CustomerID")]
public Guid ID { get; set; }
[DataMember(Name = "CustomerName")]
public string Name { get; set; }
}
Then I will have a repository interface that looks like this:
public interface ICustomerRepository
{
Customer GetCustomerByID(Guid id);
IList<Customer> List();
}
The "API" is all encapsulated within the concrete repository:
public class AcmeWSCustomerRepository : ICustomerRepository, IDisposable
{
private Acme.Services.CrmServiceSoapClient client;
public AcmeWSCustomerRepository()
: this(new Acme.Services.CrmServiceSoapClient())
public AcmeWSCustomerRepository(Acme.Services.CrmServiceSoapClient client)
{
if (client == null)
throw new ArgumentNullException("client");
this.client = client;
}
public void Dispose()
{
client.SafeClose(); // Extension method to close WCF proxies
}
public Customer GetCustomerByID(Guid id)
{
return client.GetCustomerByID(id);
}
public IList<Customer> List()
{
return client.GetAllCustomers();
}
}
Then I'll also probably have a local testing repository with just a few customers that reads from something like an XML file:
public class LocalCustomerRepository : ICustomerRepository, IDisposable
{
private XDocument doc;
public LocalCustomerRepository(string fileName)
{
doc = XDocument.Load(fileName);
}
public void Dispose()
{
}
public Customer GetCustomerByID(Guid id)
{
return
(from c in doc.Descendants("Customer")
select new Customer(c.Element("ID").Value, c.Element("Name").Value))
.FirstOrDefault();
}
// etc.
}
The point I'm trying to make here is, well, this isn't tied to any particular database. One possible source in this case is a WCF service; another is a file on disk. Neither one necessarily has a compatible "model". In this case I've assumed that the WCF service exposes a model that I can map to directly with DataContract attributes, but the Linq-to-XML version is pure API; there is no model, it's all custom mapping.
A really good domain model should actually be completely independent of the true data source. I'm always a bit skeptical when people tell me that a Linq to SQL or Entity Framework model is good enough to use throughout the entire application/site. Very often these simply don't match the "human" model and simply creating a bunch of ViewModel classes isn't necessarily the answer.
In a sense, it's actually better if you're not handed an existing relational model. It forces you to really think about the best domain model for your application, and not necessarily the easiest one to map to some database. So if you don't already have a model from a database - build one! Just use POCO classes and decorate with attributes if necessary, then create repositories or services that map this domain model to/from the API.
I think what you are looking for is really a non-DB service layer. Models, typically, are relatively simple containers for data, though they may also contain business logic. It really sounds like what you have is a service to communicate with and need a layer to mediate between the service and your application, producing the appropriate model classes from the data returned by the service.
This tutorial may be helpful, but you'd need to replace the repository with your class that interacts with the service (instead of the DB).
There is no fixed prescription of what a "Model" in MVC should be, just that it should contain the data that needs to be shown on screen, and probably also manipulated.
In a well-designed MVC application, data access is abstracted away somehow anyway, typically using some form of the Repository pattern: you define an abstraction layer (say, an IRepository interface) that defines the contract needed to get and persist data. The actual implementation will usually call a database, but in your case should call your 'service API'.
Here is an example of an MVC application that calls out to a WCF service.