EfCachingProvider and DbContext - caching

I have trying to find the way to use EFCachingProvider from Tracing and Caching Provider Wrappers for Entity Framework with Entity Framework and DbContext. I use EF 4.x DbContext Generator for c# to generate model classes.
I've already added references to EFProviderWrapperToolkit, EFCachingProvider, EFTracingProvider. I also made changes in my web.config file to :
<connectionStrings>
<add name="MyEntities" connectionString="Server=myServer;Database=MyDB;User ID=User;Password=pass;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;" providerName="EFTracingProvider" />
</connectionStrings>
<system.data>
<DbProviderFactories>
<add name="EF Caching Data Provider" invariant="EFCachingProvider" description="Caching Provider Wrapper" type="EFCachingProvider.EFCachingProviderFactory, EFCachingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>
</system.data>
But when app start, it throws an error in DbConnectionWrapper from EFProviderWrapperToolkit
in line:
DbProviderFactory factory = DbProviderFactories.GetFactory(providerInvariantName);
This is class which inherits from DbContext:
public class MyEntities : DbContext
{
public MyEntities()
: base("MyEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Entity<Product>().ToTable("Product");
modelBuilder.Entity<ProductPhoto>().ToTable("ProductPhoto");
base.OnModelCreating(modelBuilder);
}
public DbSet<Product> Product { get; set; }
public DbSet<ProductPhoto> ProductPhoto { get; set; }
}
I've already read post: USING TRACING AND CACHING PROVIDER WRAPPERS WITH CODEFIRST, but it didn't solve my problem.
Does anyone know how to do it ?

We have used the EFCachingProvider with Entity Framework and and Code First. You can see our implementation in our source code for MVCForum on CodePlex.
We found that there were many examples that showed the tracing provider but nothing that showed the caching provider with Code First.
It didn't just work with our code out of the box. We had a problem using DbContext and TransactionScope. In order to make calls that were overridden in the EFCachingProvider wrapper, and thereby redirected to the cache, we needed to use transactions from the connection, rather than TransactionScope. We couldn't get to the connection from our DbContext because it handles the connection itself, so we used the underlying ObjectContext.
private readonly IDbTransaction _transaction;
etc
_objectContext = ((IObjectContextAdapter) _context).ObjectContext;
if (_objectContext.Connection.State != ConnectionState.Open)
{
_objectContext.Connection.Open();
_transaction = _objectContext.Connection.BeginTransaction();
}
The caching provider then intercepts calls appropriately. We use the _transactionobject to issue Commit() or Rollback etc.
You can see the full implementation in our UnitOfWork class.

Related

Custom Membership and Roles in MVC3 with Forms Authentication

I use custom membership for Users and Roles in my MVC3 application. I have custom user/roles class. And I have the extended the RoleProvider and MembershipProvider classes for this.
I seem to have a case of roles going missing sometimes in my application and my Authorize [Roles='xyz'] attribute not working correctly and trying to redirect to Account/LogOn. When my user logs into the application, all I do is
if (ModelState.IsValid)
{
if (MyCustomSecurity.Login(model.UserName, model.Password, model.RememberMe))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
--other stuff
}
MyCustomSecurity.Login method basically looks up the user in the database and if valid sends a true value back.
When trying to debug the issue with my application, I came across the links below
http://www.codeproject.com/Articles/578374/AplusBeginner-27splusTutorialplusonplusCustomplusF
ASP.NET MVC Forms Authentication + Authorize Attribute + Simple Roles
Should I also be overriding FormsAuthentication_OnAuthenticate() as mentioned in this link? Or does the RoleProvider extended class take care of this?
Thank You
If you use roles in AuthorizeAttribute, and roles are your own classes, so you need to override RoleProvider, especially method GetRolesForUser:
public class CustomRoleProvider : RoleProvider
{
public override string[] GetRolesForUser(string username)
{
// put your logic to discover which roles the user has
}
}
After doing that, you have to register you CustomRoleProvider in Web.Config:
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear/>
<add name="CustomRoleProvider" type="%YOURNAMESPACE%.CustomRoleProvider" />
</providers>
</roleManager>

Entity framework 4.1 won't connect to SQL Server after using Database First approach

I've created a new MVC 3 website using EF 4.1 with DB first approach. I've created the edmx file and then the DBContext (the new 4.1 feature) classes. all went well.
Then, I've created new controllers using the automatic creation for DBContext. All wen't great.
Now, that I'm trying to fire up the website it won't connect to the connection string itself created.
Here is the connection string:
<add name="PizzaByMeEntities"
connectionString='metadata=res://*/Models.PizzaByMeModel.csdl|
res://*/Models.PizzaByMeModel.ssdl|
res://*/Models.PizzaByMeModel.msl;
provider=System.Data.SqlClient;
provider connection string="data source=(local);
initial catalog=PizzaByMe;
integrated security=True;
pooling=False;
multipleactiveresultsets=True;
App=EntityFramework;"'
providerName="System.Data.EntityClient" />
When I fire up the website I get:
A network-related or instance-specific error occurred while
establishing a connection to SQL Server. The server was not found or
was not accessible. Verify that the instance name is correct and that
SQL Server is configured to allow remote connections. (provider: SQL
Network Interfaces, error: 26 - Error Locating Server/Instance
Specified)
The strange part is that if I remove the connection string - I still get the exact same error. I guess that the EF just can't find the Connection String even when it's there.
Any ideas?
Thanks!
EDIT:
My DBContext is as follows:
public partial class PizzaByMeEntities : DbContext
{
public PizzaByMeEntities()
: base("name=PizzaByMeEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<X> Xs{ get; set; }
public DbSet<Y> Ys{ get; set; }
public DbSet<Z> Zs{ get; set; }
}
EDIT 2:
the working connection string is this:
<add name="PizzaByMe" connectionString="Data Source=(local);initial catalog=PizzaByMe;integrated security=True;pooling=False;multipleactiveresultsets=True;" providerName="System.Data.EntityClient" />
Though to make it work - I just used direct ADO.NET connection.
Your derived DbContext class must have the same name as your connection string if you have only implemented a default constructor (or no constructor at all)
public PizzaByMeEntities : DbContext
{
public PizzaByMeEntities()
{
// ...
}
}
If your context has another name then you must specify the name of the connection string in the constructor:
public PizzaByMeContext : DbContext
{
public PizzaByMeContext() :
base("name=PizzaByMeEntities")
{
// ...
}
}
Here are details about connections and connection strings with DbContext: http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx
Edit: Another guess
The connection string must be in the web.config of your MVC app, not in an app.config of a class library project where you possibly have your EF model and DbContext. Is it?
Phewwww.... figured it out!!!
The Context object that the controller created (when you use new context) it created the object without the constructor that chooses the connection string. So it tried to use some non-existing connection string.
For conclusion - any object deriving from DBContext should use a constructor that would specify the connection string.
Thanks guys for helping me out :))

Using Ninject with a Custom Role provider in an MVC3 app

I'm trying to use a custom role provider in an MVC3 app. I've already got the membership provider working ok using Ninject but can't seem to get the role provider working. The Membership provider doesn't require a parameterless constructor but role provider does. Here's some code snippets:
Web.config
<membership>
<providers>
<clear/>
<add name="MyMembershipProvider" type="MyApp.Models.NHibernateMembershipProvider"
applicationName="myApp" />
</providers>
</membership>
<roleManager enabled="true">
<providers>
<add name="MyRolesProvider" type="MyApp.Models.NHibernateRoleProvider"
applicationName="myApp" />
</providers>
</roleManager>
I have a Ninject module.
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
this.Bind<ISession>().ToMethod(
x => MyApp.MvcApplication.SessionFactoryData.GetCurrentSession());
// Respository
this.Bind<IUserRepository>().To<UserRepository>();
this.Bind<MembershipProvider>().To<NHibernateMembershipProvider>();
this.Bind<RoleProvider>().To<NHibernateRoleProvider>();
}
}
The custom Membership provider
public class NHibernateMembershipProvider : MembershipProvider
{
private IUserRepository _repo;
public NHibernateMembershipProvider(IUserRepository repository)
{
_repo = repository;
}
...
The role provider
public class NHibernateRoleProvider : RoleProvider
{
private IUserRepository _repo;
public NHibernateRoleProvider(IUserRepository repository)
{
_repo = repository;
}
...
I then configure my controller to require an authorize
[Authorize(Roles="Admin")]
public ActionResult Edit(int? id)
{
...
I get this error when starting the app.
Parser Error Message: No parameterless constructor defined for this object.
Source Error:
Line 49: <roleManager enabled="true">
Line 50: <providers>
Line 51: <add name="MyRolesProvider" type="MyApp.Models.NHibernateRoleProvider"
Line 52: applicationName="myApp" />
Line 53: </providers>
I can access the users through the membership provider, so the repository is being injected ok, but the roles provider seems to be different. Why does the role provider require a constructor-less parameter? Is there a simple way to get the role provider to work with Ninject. Any help appreciated.
Since the role provider, in this case the NHibernateRoleProvider is instantiated by the ASP.NET framework the best solution is to use the service locator pattern. The service locator pattern is normally considered to be an anti-pattern but sometimes you have to be pragmatic and accepted the limitation on the framework that is being used (in this case the ASP.NET framework).
Assuming you are using an implementation of the IDependencyResolver interface for Ninject. The following code should work.
public class NHibernateMembershipProvider : MembershipProvider
{
private IUserRepository _repo;
public NHibernateMembershipProvider()
{
_repo = DependencyResolver.Current.GetService<IUserRepository>();
}
// ...
}
Alternatively, if you're using the Ninject.Web.Mvc nuget package you can always use property injection on your role provider as illustrated here:
ASP.NET MVC 3 Ninject Custom Membership and Role Provider

ASP.NET MVC3 database deployment

I have created application in mvc3 and I used the default account controller for my users.
I followed instructions from http://www.asp.net/mvc/tutorials/authenticating-users-with-forms-authentication-cs to put all tables (from aspnetdb) in one database.
My trouble is how to set webconfig and connection string corectly?
I set the conn string to my databse but if I try to register Visual studio create aspnetdb and put my user info there.
I am trying to find solution to stop vs creating aspnetdb.
My hosting provider is http://www.inside.hr it is hosting company from Croatia
If your shared hosting environment only allows you to use one database, you can add the ASP.NET Membership database tables to your existing database. Joe Stagner has a walkthrough on how to do that here.
Can you update your question to tell us where you're hosting? That will help.
I'm not sure if I follow you correctly, but did you try something like this:
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
<add name="MyDevArmyDB" connectionString="Data Source=DATASOURCE;Initial Catalog=devarmydb;Persist Security Info=True;User ID=USERID;Password=PASSWORDSTRING"
providerName="System.Data.SqlClient" />
</connectionStrings>
DATASOURCE- replace with the address of your database
USERID- replace with the actual user id
PASSWORDSTRING- replace with the actual password
Accessing the DB is done like this:
public class SqlUserRepository : IUserRepository
{
private DataContext dataContext;
private Table<User> usersTable;
public IQueryable<User> Users { get { return usersTable; } }
public SqlUsersRepository(string databaseName)
{
HttpRequestWrapper request = new HttpRequestWrapper(System.Web.HttpContext.Current.Request);
Configuration config = WebConfigurationManager.OpenWebConfiguration(request.ApplicationPath);
dataContext = new DataContext(config.GetConnetionString(databaseName));
}
}
Note that GetConnectionString is an extension function which supports encryption/decryption of the connection string (if you decide to protect the connection string):
public static class ConfigExtension
{
public static string GetConnetionString(this Configuration config, string databaseName, string provider = "RSAProtectedConfigurationProvider")
{
string sectionName = "connectionStrings";
ConfigurationSection section = config.GetSection(sectionName);
if (section != null && !section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection(provider);
config.Save();
}
return WebConfigurationManager.ConnectionStrings[databaseName].ConnectionString;
}
}

Extending Enterprise Library Caching Block - how to get instance of MyCacheManager?

Since the default implementation of CacheManager doesn't provide GetItemsOfType<> (and many others) I thought of building my own:
[ConfigurationElementType(typeof(CustomCacheManagerData))]
public class MyCacheManager : ICacheManager
{
//The same constructor as in CacheAppBlock - CacheManager, but it's public here:
public MyCacheManager(Cache realCache, BackgroundScheduler scheduler, ExpirationPollTimer pollTimer)
{
this.realCache = realCache;
this.scheduler = scheduler;
this.pollTimer = pollTimer;
}
//the other code is basically copy/paste from CacheManager in EntLib, with some of my methods like:
public T[] GetItemsOfType<T>()
{
return realCache.CurrentCacheState.Values.OfType<T>().ToArray();
}
//I also have some other custom code on the underlying Hashtable in realCache
}
The cofiguration part (the type part points to my class, encryption isn't used):
<cachingConfiguration defaultCacheManager="SomeCacheManager">
<cacheManagers>
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
type="MyNamespace.MyCacheManager, MyNamespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
name="SomeCacheManager" />
</cacheManagers>
<backingStores>
<add encryptionProviderName="" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Null Storage" />
</backingStores>
</cachingConfiguration>
The problem I'm facing now is how to create MyCacheManager?
The:
mCityCacheManager = (MyCacheManager)CacheFactory.GetCacheManager("SomeCacheManager");
throws exception saying there's no Constructor in MyCacheManager (but there is, same as in EntLib's CacheManager only they are public in my class...)
That's because MyCacheManager isn't exactly like the EntLib one! And I don't mean the extra methods. Take a look at the declarations.
Original CacheManager:
[ConfigurationElementType(typeof(CacheManagerData))]
public class CacheManager : IDisposable, ICacheManager
MyCacheManager:
[ConfigurationElementType(typeof(CustomCacheManagerData))]
public class MyCacheManager : ICacheManager
Other than the name difference (and you didn't extend IDisposable), notice the element type attributes.
You're using (you have to) the Custom one. The custom one requires a constructor that takes a NameValueCollection as a parameter.
public MyCacheManager(NameValueCollection collection)
It is a generic configuration driver, so to speak, and as such it cannot be expected to know to create your instance with a 3 parameter constructor consisting of a Cache object, scheduler, and poll timer like you've got. Instead, it passes in these values (or anything you've got set as attributes in the configuration file) via a basic NameValueCollection which you'll have to parse manually.
See also:
http://bloggingabout.net/blogs/dennis/archive/2009/10/22/create-a-custom-caching-manager-for-enterprise-library-4.aspx

Resources