Is it alright to hang a shared property off of the global.asax (MvcApplication class)?
And then access it like so in other area:
MvcApplication.[SharedPropertyName]
Edit
What I am trying to do is have a globally accessible property that is my application settings.
I am using an XmlSerializer to serialize/deserialize an object that holds all of these properties. It works great, but the Load method on the ApplicationSettings is shared and returns an instance of the ApplicationSettings, so some of the other ideas people have suggested around singelton is not going to work. Here is the ApplicationSettings class:
Public Class ApplicationSettings
#Region "Members/Properties"
Public Property Property1 As String
Public Property Property2 As String
...
#End Region
#Region "Methods"
Public Shared Function GetFilePath() As String
Return HttpContext.Current.Server.MapPath("/Bin/Settings.config")
End Function
Public Shared Function Load() As ApplicationSettings
Try
Dim Serializer As XmlSerializer
Dim Settings As ApplicationSettings
Using Reader As New StreamReader(GetFilePath)
Serializer = New XmlSerializer(GetType(ApplicationSettings))
Settings = CType(Serializer.Deserialize(Reader), ApplicationSettings)
Reader.Close()
End Using
Return Settings
Catch ex As Exception
'Return New ApplicationSettings
Return Nothing
End Try
End Function
Public Sub Save()
Dim Serializer As XmlSerializer
Using Writer As New StreamWriter(GetFilePath, False)
Serializer = New XmlSerializer(GetType(ApplicationSettings))
Serializer.Serialize(Writer, Me)
Writer.Flush()
Writer.Close()
End Using
End Sub
#End Region
End Class
Not recommended. If you need a globally accessible variable or property, that's more suited to a base class that your classes inherit from.
This link gives an example of a controller base class.
EDIT:
Based off your edit, it's tough to recommend something specific because how those settings are used can drive your approach. Here's some general tips:
I'd split out your settings into a series of base classes that are distinct in their area of concern. So settings regarding FunctionalityX lives within the class dealing with FunctionalityX.
I'd leverage your web.config. I'm sure you're already doing this, but just make sure that you're not duplicating configuration efforts. The Web.Config is the right place for most of it and you can add more. Classes already exist for pulling configuration information out of the web config.
Alright, with that having been said, barring those two paths:
I'd set your class to static so you can just reference your class from anywhere without instantiation like this: ApplicationSettings.SettingValue.
I'd have explicit settings properties on your ApplicationSettings class and reference them directly that way. If they aren't instantiated, you can lazy load them from the XML as they are needed.
I'd cache your settings if they aren't dynamic.
So there's some general tips that might yield a better solution. It's hard to recommend something concrete without further information on how it'll be used.
FINAL EDIT:
After some discussion in the comments below, we found that this resource here fixed the OP's issue:
http://haacked.com/archive/2007/03/12/custom-configuration-sections-in-3-easy-steps.aspx
I would say no. There likely is a better way to do what you are attempting to do.
Related
I am developing an MVC app to serve multiple domains - each is a branch of a larger company.
A LocalBranch class stores details such as phone, address, email, location coordinates etc.
I want to create a single instance of this class per http request and have it available throughout the application - from within controllers, views, some helper classes and other code.
Is there a recommended way of doing this?
Right now I have it as a property on a BaseController and use ViewBagto pass it to views. But I would prefer it strongly typed in Views if possible.
I don't want to put it in an application variable, because we need to serve different values to different domains.
I would rather avoid a session variable if possible because we might scale up to use multiple servers in the future, and I've heard this doesn't play well with sessions.
Please feel free to update tags / title if you think there is a clearer way of expressing what I'm after. Thank you.
The best way to maintain your state in a web application per request is simply use the HttpContext class.
You need to store your state(LocalBranch) as an Item in the HttpContext:
HttpContext.Current.Items.Add("LocalBranch", GetLocalBranch());
You can fetch the Item all across your application like this:
LocalBranch branch = HttpContext.Current.Items["LocalBranch"] as LocalBranch;
The Items property is simply a key value Dictionary. The value is an object. You will have to check for nulls and this is really similar to the Session object you know. The main difference is the scope. The HttpContext is a dot net object that has a lifetime of an http request.
Now using the HttpContext the way I've shown you is the simplest way to do it.
You can go two steps forward and use a framework called Unity and add a lifetime to your objects.
Unity does much more and the lifetime management is just one gem.
You can create a custom HttpContext lifetime that generates objects per request. Something like this.
And them all you need to do is:
1.Register you LocalBranch class with the HttpContext lifetime.
2.Add a static Current property which will use the Unity container and resolve the correct instance of LocalBranch.
3.Use it something like this: LocalBranch.Current
BTW, you can use Unity's dependency injection for injecting objects into controllers and other modules. That's a better practice then just using the static Current property.
You kind of have two questions here. The first is "How do I create a single instance of this class per HttpRequest?" The second is "How do I make this available to strongly typed views?"
The first has pretty much been answered by #amir-popovich to use dependency injection. However, FWIW I would probably use Ninject instead of Unity (just preference, really) and I would probably implement it differently. I would not use HttpContext, and simply build a service (which is instanciated using Ninject's OnePerHttpRequest Module, passing the domain as an argument to get the proper values).
Then, in order to add these LocalBranch values to your strongly typed View Model, you can first create a base view model which holds this type:
public class BaseViewModel
{
public LocalBranch Branch {get;set;}
}
Then, make all of your current view models inherit this base type
public MyViewModel : BaseViewModel
{
public string SomeValue {get;set;}
}
Then in your controller, it is easy enough to add these values from the service you created from the first step
public ActionResult SomeAction()
{
var vm = new MyViewModel();
vm.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
//do other stuff
return View(vm);
}
However, that gets pretty tedious to add that to each controller action, so you can instead create a Result Filter to add it for you:
public class LocalBranchResultFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
//This method gets invoked before the ActionResult is executed.
filterContext.Controller.ViewData.Model.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
}
}
Now, you can just decorate your Controller and/or Actions with the filter (you could even set it in the Global Filters if you want).
You can embed the child actions into your layout or a view. You can even cache its output so you don't keep re-querying the database.
controller
[ChildActionOnly]
[OutputCache(Duration=500, VaryByParam="*")]
public ActionResult Info()
{
var localBranch = db.GetLocalBranch();
return PartialView("_Info", localBranch);
}
_Info view
This bit will get inserted into your other views
#model LocalBranch
<span>#Model.address</span>
<span>#Model.phone</span>
Use in _Layout or other view
<p>lorem ipsum...</p>
#Html.Action("Info")
I have an ASP.NET MVC application which uses MEF to implement a plugin framework. Plugins are separate DLLs that exist in the application's bin directory. Plugins usually export one or more controllers like this...
<Export(GetType(IController))>
<MYAPP_Interfaces.Attributes.MVCPluginMetadata(
"SomePlugin",
"A Description for the plugin",
"A Readable Name",
{"ScriptsForThePlugin.js"},
{"StylesForThePlugin.css"},
Enumerations.MVCPluginType.DataView,
"DefaultActionName")>
<PartCreationPolicy(CreationPolicy.NonShared)>
Public Class MyPluginController
Inherits System.Web.Mvc.Controller
<Import()>
Private m_objHost As IWebHost
... and so on.
This all works fine, the host app includes all controllers in an ImportMany property, and composes itself upon creation in the usual way. So m_objHost is populated automagically and the controller has access to all the things the host application provides, like logging and information about the user and what they're currently working on and all that.
My question has to do with my models, and any DAL or utility classes that I have in a plugin. These classes usually have need of information from the IWebHost object. However, the host doesn't need to know about these classes, so they are not included in composition. Since they are not composed, if they want an IWebHost reference they each have to compose themselves upon instantiation, like this:
Public Class MyModel
<Import()>
Private m_objHost As IWebHost
<Import()>
Private m_objLog As ILog
Public Sub New()
Compose()
End Sub
...
Private Sub Compose()
Try
Dim objCatalog As New AggregateCatalog
objCatalog.Catalogs.Add(New DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory & "bin"))
Dim container As New CompositionContainer(objCatalog)
container.ComposeParts(Me)
Catch ex As Exception
If m_objLog IsNot Nothing Then
m_objLog.writeError(ex)
End If
End Try
End Sub
End Class
So my main question can be broken into two parts:
Is there any noticeable performance problem with having, say, 20 or so classes that perform composition whenever they are instantiated? I currently only have a few, and if there is a hit it's not noticeable. In other words, do I actually need to change this strategy? It violates DRY because I have a Compose method in every class, but I can learn to live with it.
Is there a better way? How can I handle a single composition in the main application that takes care of populating all of the classes in the plugins, including those not imported in the class performing the main composition?
I've considered the following:
Having all models and utility classes and whatever implement a marker interface, export them all using that interface as a contract, and importing them in the host class, even though the host class doesn't need them. I think this is an even cruddier design than what I have, and I don't want to do it. I'm willing to listen to arguments in favor of this, though.
Having a class in each plugin that needs it that implements IWebHost that acts as a wrapper for the class exported by the main app. I'd still have to do composition in each plugin, but at least it would only be once per plugin. This one seems okay to me.
Thanks in advance for any help you can give, and for reading this whole novel of a question.
I wound up adding a class like the one below to the plugins that need it. I have a project template for plugins, so I'll probably just add this class to that template.
Any class that needs something from the host can access it by calling PluginUtility.Host.
Public Class PluginUtility
<Import()>
Private m_objHost As IWebHost
Private Shared m_objInstance As PluginUtility
Private Sub New()
Compose()
End Sub
Public Shared ReadOnly Property Host As IWebHost
Get
If m_objInstance Is Nothing Then
m_objInstance = New PluginUtility
End If
Return m_objInstance.m_objHost
End Get
End Property
Private Sub Compose()
Try
Dim objCatalog As New AggregateCatalog
objCatalog.Catalogs.Add(New DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory & "bin"))
Dim container As New CompositionContainer(objCatalog)
container.ComposeParts(Me)
Catch ex As Exception
Console.Write("Could not compose to get a reference to the host")
End Try
End Sub
End Class
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 was creating an mvc application and i had a model class with a dbcontext function the variables were in the same file. I added another field and changed the code in the edit create delete details and index views but i now get an error saying
"The model backing the 'GameDBContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data."
Imports System.Data.Entity
Public Class Game
Public Property ID() As Integer
Public Property Name() As String
Public Property Genre() As String
Public Property Price() As Decimal
Public Property Developer() As String
End Class
Public Class GameDBContext
Inherits DbContext
Public Property Games() As DbSet(Of Game)
End Class
you need to add a initializer method to the Application_Start method in Global.asax file. Ex:-
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<GameDBContext>());
Since it sounds like you're using a code first approach in developing your application, here are a couple of links that might help you:
code first development with entity framework 4
Code First/Entity Framework 4.1 Videos and Articles on MSDN
All of these can give you a better understanding of what is happening and how to work around having your database change on you.
In short, since you added another property, the entity framework table in your database is now longer in sync with your class. Since it's no longer in sync, you must manually delete this database in order to regenerate it, or you must create an initialization for the database. All of these concepts are better described in the links I have provided.
Good luck, and hope these help you some.
I want to use Ninject in my Windows application and I want to know if there is best practices that I can do; strategies to find a balance between performance and maintenance.
The problem with Windows application and Web application is that in Web application, there is a scope easy to define that is the context but with Windows application, you have no scope that is easy to use form after form.
As example, I have a service that query the database. This service have a constructor and received a UnitOfWork. With Ninject, I can create a property marked as to be injected but if I do that, each time I will create this service, a new connection will be created to the database.
Just for this reason, I must manually create my services to control the number of connection created and no dependency injector can be used.
I have found that you can call the Inject method after created the service for inject dependencies but I'm sure I can use a better strategy.
With Ninject, you can have Ninject scope lifetimes of your injected dependencies to any object you want to provide (not just Singleton, Request, Thread, and Transient scopes).
From the Ninject Documentation Wiki:
You can also easily define you own
scopes using the .InScope(object o)
method.
You'll find some actual detail about how object scoping works in this Ninject Google Groups question & answer.
I finally found what I searching for.
Create a class that inherits from 'Ninject.Activation.Provider(of T)'
Overrrides the function 'CreateInstance'
Bind your interface with that 'Bind(Of [Your interface]).ToProvider([Your provider class])'
And now, you will be able to control each instance created that are associated with the specified interface.
Note that you can pass a type or an instance to the provider parameter of the Bind method. You can with an instance create a provider before binding your interfaces and use this provider in your code when you want to create a new instance.
The provider in conjunction with InScope allows great flexibility for each place where you want to have and instance of an object that can be injected automatically and have a determined scope.
Here is an example:
Public Interface IConnection
End Interface
Public Class Connection
Implements IConnection
End Class
Imports Ninject
Public Class StandardModule
Inherits Ninject.Modules.NinjectModule
Public Property ConnectionProvider As ConnectionProvider
Public Overrides Sub Load()
Bind(Of IConnection).ToProvider(Me.ConnectionProvider)
End Sub
End Class
Public Class ConnectionProvider
Inherits Ninject.Activation.Provider(Of IConnection)
Public Property Connection As IConnection
Protected Overrides Function CreateInstance(ByVal context As Ninject.Activation.IContext) As IConnection
Return Me.Connection
End Function
End Class
Imports Ninject
Module EntryPoint
Sub Main()
Dim provider As New ConnectionProvider
Dim standardModule As New StandardModule
Dim connection As IConnection
Dim kernel As New Ninject.StandardKernel()
standardModule.ConnectionProvider = provider
kernel = New Ninject.StandardKernel(standardModule)
' Here you should use a factory instead of create an instance directly but
' for demonstration, it show how an instance can be propagated to object created
' by NInject.
provider.Connection = New Connection
connection = kernel.Get(Of IConnection)()
End Sub
End Module
This article by Ayende in MSDN Magazine is ostensibly about NHibernate, and mentions the word inject only once (and that only wrt AOP), but the phrasing of your question suggests to me it'll be great food for thought as you consider how to architect your app.
You can also make your frameworks depend on a factory instance, and rely on the factory to perform your connection pooling.
Alternatively, you can use Ninject itself to always use the same object instance for the particular type.