طراحی افزونه پذیر با ASP.NET MVC 4.x/5.x - قسمت سوم
نویسنده: وحید نصیری
تاریخ: ۱۳۹۴/۰۱/۲۸ ۱۲:۱۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using System.Data.Entity.ModelConfiguration;
namespace MvcPluginMasterApp.Plugin1.DomainClasses
{
public class News
{
public int Id { set; get; }
public string Title { set; get; }
public string Body { set; get; }
}
public class NewsConfig : EntityTypeConfiguration<News>
{
public NewsConfig()
{
this.ToTable("Plugin1_News");
this.HasKey(news => news.Id);
this.Property(news => news.Title).IsRequired().HasMaxLength(500);
this.Property(news => news.Body).IsOptional().IsMaxLength();
}
}
} PM> install-package EntityFramework
public class MvcPluginMasterAppContext : DbContext, IUnitOfWork
{
public DbSet<Category> Categories { set; get; }
public DbSet<Product> Products { set; get; } namespace MvcPluginMasterApp.PluginsBase
{
public interface IUnitOfWork : IDisposable
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveAllChanges();
void MarkAsChanged<TEntity>(TEntity entity) where TEntity : class;
IList<T> GetRows<T>(string sql, params object[] parameters) where T : class;
IEnumerable<TEntity> AddThisRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
void SetDynamicEntities(Type[] dynamicTypes);
void ForceDatabaseInitialize();
void SetConfigurationsAssemblies(Assembly[] assembly);
}
} namespace MvcPluginMasterApp.DataLayer.Context
{
public class MvcPluginMasterAppContext : DbContext, IUnitOfWork
{
private readonly IList<Assembly> _configurationsAssemblies = new List<Assembly>();
private readonly IList<Type[]> _dynamicTypes = new List<Type[]>();
public void ForceDatabaseInitialize()
{
Database.Initialize(force: true);
}
public void SetConfigurationsAssemblies(Assembly[] assemblies)
{
if (assemblies == null) return;
foreach (var assembly in assemblies)
{
_configurationsAssemblies.Add(assembly);
}
}
public void SetDynamicEntities(Type[] dynamicTypes)
{
if (dynamicTypes == null) return;
_dynamicTypes.Add(dynamicTypes);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
addConfigurationsFromAssemblies(modelBuilder);
addPluginsEntitiesDynamically(modelBuilder);
base.OnModelCreating(modelBuilder);
}
private void addConfigurationsFromAssemblies(DbModelBuilder modelBuilder)
{
foreach (var assembly in _configurationsAssemblies)
{
modelBuilder.Configurations.AddFromAssembly(assembly);
}
}
private void addPluginsEntitiesDynamically(DbModelBuilder modelBuilder)
{
foreach (var types in _dynamicTypes)
{
foreach (var type in types)
{
modelBuilder.RegisterEntityType(type);
}
}
}
}
} namespace MvcPluginMasterApp.PluginsBase
{
public interface IPlugin
{
EfBootstrapper GetEfBootstrapper();
//...به همراه سایر متدهای مورد نیاز
}
public class EfBootstrapper
{
/// <summary>
/// Assemblies containing EntityTypeConfiguration classes.
/// </summary>
public Assembly[] ConfigurationsAssemblies { get; set; }
/// <summary>
/// Domain classes.
/// </summary>
public Type[] DomainEntities { get; set; }
/// <summary>
/// Custom Seed method.
/// </summary>
public Action<IUnitOfWork> DatabaseSeeder { get; set; }
}
} namespace MvcPluginMasterApp.Plugin1
{
public class Plugin1 : IPlugin
{
public EfBootstrapper GetEfBootstrapper()
{
return new EfBootstrapper
{
DomainEntities = new[] { typeof(News) },
ConfigurationsAssemblies = new[] { typeof(NewsConfig).Assembly },
DatabaseSeeder = uow =>
{
var news = uow.Set<News>();
if (news.Any())
{
return;
}
news.Add(new News
{
Title = "News 1",
Body = "news 1 news 1 news 1 ...."
});
news.Add(new News
{
Title = "News 2",
Body = "news 2 news 2 news 2 ...."
});
}
};
} [assembly: PreApplicationStartMethod(typeof(EFBootstrapperStart), "Start")]
namespace MvcPluginMasterApp
{
public static class EFBootstrapperStart
{
public static void Start()
{
var plugins = SmObjectFactory.Container.GetAllInstances<IPlugin>().ToList();
using (var uow = SmObjectFactory.Container.GetInstance<IUnitOfWork>())
{
initDatabase(uow, plugins);
runDatabaseSeeders(uow, plugins);
}
}
private static void initDatabase(IUnitOfWork uow, IEnumerable<IPlugin> plugins)
{
foreach (var plugin in plugins)
{
var efBootstrapper = plugin.GetEfBootstrapper();
if (efBootstrapper == null) continue;
uow.SetDynamicEntities(efBootstrapper.DomainEntities);
uow.SetConfigurationsAssemblies(efBootstrapper.ConfigurationsAssemblies);
}
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MvcPluginMasterAppContext, Configuration>());
uow.ForceDatabaseInitialize();
}
private static void runDatabaseSeeders(IUnitOfWork uow, IEnumerable<IPlugin> plugins)
{
foreach (var plugin in plugins)
{
var efBootstrapper = plugin.GetEfBootstrapper();
if (efBootstrapper == null || efBootstrapper.DatabaseSeeder == null) continue;
efBootstrapper.DatabaseSeeder(uow);
uow.SaveAllChanges();
}
}
}
}
DatabaseSeeder = uow =>
{
var news = uow.Set<News>(); public class CmsUser : IdentityUser
{
public string DisplayName { get; set; }
} public class Post
{
private IList<string> _tags = new List<string>();
public int id { get; set; }
public string name { get; set; }
public string slug { get; set; }
public string description { get; set; }
public DateTime? publishTime { get; set; }
public string content { get; set; }
public IList<string> tags
{
get { return _tags; }
set { _tags = value; }
}
public string CombineTags
{
get { return string.Join(",", _tags); }
set { _tags = value.Split(',').Select(x => x.Trim()).ToList(); }
}
public string AuthorID { get; set; }
// [ForeignKey("AuthorID")]
// public CmsUser Author { get; set; }
}
public class Cmscontex : IdentityDbContext<CmsUser>
public class UIAppContext : DbContext, IUnitOfWork
ولی در عمل در EfBootstrapper باید برای کلیه کلاسهای Ef مقدار DomainEntities و برای کلیه کلاسهای Fluent Api مقدار ConfigurationsAssemblies مشخص شود . در حالی که در لینک هایی که ^ و ^ کلیه کلاس هایی که از BaseEntity مشتق شده اند به Context اضافه شده و نیازی به معرفی ندارند و کلاسها تنظیمات FluentApiها نیز از روی nameSpace مشخص شده اضافه میشوند.
بهتر نیست از BaseEntity استفاده بشود؟
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
AddConfigurationsFromAssemblies(modelBuilder);
AddPluginsEntitiesDynamically(modelBuilder);
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<AppUser>().ToTable("Users");
modelBuilder.Entity<CustomRole>().ToTable("Roles");
modelBuilder.Entity<CustomUserClaim>().ToTable("UserClaims");
modelBuilder.Entity<CustomUserRole>().ToTable("UserRoles");
modelBuilder.Entity<CustomUserLogin>().ToTable("UserLogins");
} Additional information: Method not found: 'Void System.Data.Entity.DbModelBuilder.RegisterEntityType(System.Type)'.
PM> update-package
No default Instance is registered and cannot be automatically determined for type 'Microsoft.Owin.Security.DataProtection.IDataProtectionProvider' There is no configuration specified for Microsoft.Owin.Security.DataProtection.IDataProtectionProvider 1.) new ApplicationUserManager(*Default of IUserStore<AppUser, Int32>*, *Default of IApplicationRoleManager*, *Default of IDataProtectionProvider*, *Default of IIdentityMessageService*, *Default of IIdentityMessageService*, *Default of IUserService*) 2.) PPU.Plugin.Accounting.Service.ApplicationUserManager 3.) Instance of PPU.Plugin.Accounting.Service.Contract.IApplicationUserManager (PPU.Plugin.Accounting.Service.ApplicationUserManager) 4.) new HomeController(*Default of IApplicationUserManager*, *Default of IApplicationSignInManager*, *Default of IAuthenticationManager*, *Default of IProfileService*, *Default of IUserService*, *Default of IUnitOfWork*) 5.) PPU.Plugin.Accounting.Areas.Account.Controllers.HomeController 6.) Instance of PPU.Plugin.Accounting.Areas.Account.Controllers.HomeController 7.) Container.GetInstance(PPU.Plugin.Accounting.Areas.Account.Controllers.HomeController)
[assembly: OwinStartupAttribute(typeof(PPU.WebUi.Startup))]
[ForeignKey("UserId")]
public virtual User User { set; get; }
public int UserId { set; get; } var userNewsList = _news.Include(x=>x.User).Where(x=>x.UserId == 1).ToList();
XCopy "$(ProjectDir)$(OutDir)*" "$(SolutionDir)MvcPluginMasterApp\bin\" /S /Y
var pluginUrl = plugin.GetMenuItem(this.Request.RequestContext).Url; return Redirect(pluginUrl + "/path1/path2/path3?queryStringValue1=" + Server.UrlEncode(searchTerm));
public class NewsItemConfig : EntityTypeConfiguration<NewsItem>
{
public NewsItemConfig()
{
HasMany(a => a.Tags).WithMany().Map(m =>
{
m.MapLeftKey("TagId");
m.MapRightKey("NewsItemId");
m.ToTable("NewsItemTag");
});
}
} var news= from p in ctx.NewsItems
from t in p.Tags
where t.Name == "Tag1"
select p; @using MvcPluginMasterApp.IoCConfig
@using MvcPluginMasterApp.PluginsBase
@{
var plugins = SmObjectFactory.Container.GetAllInstances<IPlugin>().ToList();
}
@foreach (var plugin in plugins)
{
var menuItem = plugin.GetMenuItem(this.Request.RequestContext);
<li>
<a href="@menuItem.Url">@menuItem.Name</a>
</li>
} string CreateSqlSchema { get;} An exception of type 'System.Data.SqlClient.SqlException' occurred in EntityFramework.SqlServer.dll but was not handled in user code Additional information: CREATE FULLTEXT CATALOG statement cannot be used inside a user transaction.
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql, parameters);