ASP.NET MVC实现通用设置
网站中的设置实现方式有好几种,其中有将设置类序列化然后保存到文件中(例如使用XML序列化然后以XML形式保存在文件中),或者将设置信息保存到数据库中。
保存到数据库中的方式就是将设置的项作为key,设置的值作为value,以key-value(键值对)的形式保存。
下面使用保存到数据库中的例子来说明,首先是设置信息数据库表结构:

Name是设置项,Value是设置值。对应的实体类如下:
public class Setting : ISettings
{
public int Id { get; set; } public string Name { get; set; } public string Value { get; set; }
}
这里是使用Entity Framework,下面是数据库上下文实体类:
public partial class SettingContext : DbContext
{
public SettingContext():base("name=MyConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer< SettingContext>(null);
modelBuilder.Configurations.Add(new SettingMap());
base.OnModelCreating(modelBuilder);
} public IQueryable<Setting> Table
{
get
{
return Set<Setting>();
}
}
public IQueryable<Setting> TableNoTracking
{
get
{
return Set<Setting>().AsNoTracking();
}
}
public void Insert(Setting entity)
{
if (entity == null)
{
throw new ArgumentException("entity");
}
Set<Setting>().Add(entity);
SaveChanges();
} public void Update(Setting entity)
{
if (entity == null)
{
throw new ArgumentException("entity");
}
Set<Setting>().Attach(entity);
Entry(entity).State = EntityState.Modified;
SaveChanges();
}
/// <summary>
/// 加载"设置"
/// </summary>
/// <typeparam name="T">设置必须实现接口ISettings</typeparam>
/// <returns></returns>
public T LoadSetting<T>() where T : ISettings, new()
{
//创建设置实例,然后再对其属性赋值
var setting = Activator.CreateInstance<T>();
Type t = typeof(T); //获取所有的属性
PropertyInfo[] props = t.GetProperties();
//获取数据库中所有的设置
var allSetting = TableNoTracking.ToList();
if (allSetting!= null && allSetting.Count > )
{
foreach (PropertyInfo p in props)
{
if (!p.CanRead || !p.CanWrite)
{
continue;
}
string key = t.Name + "." + p.Name;
key = key.Trim().ToLowerInvariant(); //转换为小写
var obj = allSetting.Where(s => s.Name == key).FirstOrDefault();
if (obj == null)
{
continue;
}
string valueStr = obj.Value;
//判断是否可以转换为
if (!TypeDescriptor.GetConverter(p.PropertyType).CanConvertFrom(typeof(string)))
{
continue;
}
if (!TypeDescriptor.GetConverter(p.PropertyType).IsValid(valueStr))
{
continue;
}
object value = TypeDescriptor.GetConverter(p.PropertyType).ConvertFromInvariantString(valueStr);
p.SetValue(setting, value);
}
}
return setting;
}
/// <summary>
/// 保存设置
/// </summary>
/// <typeparam name="T">设置必须实现接口ISettings</typeparam>
/// <param name="setting"></param>
public void SaveSetting<T>(T setting) where T : ISettings, new()
{
var allProperties = typeof(T).GetProperties();
var allSettings = Table.ToList();
foreach (PropertyInfo prop in allProperties)
{
if (!prop.CanRead || !prop.CanWrite)
{
continue;
}
//判断是否可以转换
if (!TypeDescriptor.GetConverter(prop.PropertyType).CanConvertFrom(typeof(string)))
{
continue;
}
string key = typeof(T).Name + "." + prop.Name;
key = key.Trim().ToLowerInvariant();
dynamic value = prop.GetValue(setting, null);
if (value == null)
{
value = "";
}
var obj = allSettings.Where(s => s.Name == key).FirstOrDefault();
//需要转换为string
string valueStr = TypeDescriptor.GetConverter(prop.PropertyType).ConvertToInvariantString(value);
//已存在设置则更新,不存在则添加
if (obj != null)
{
obj.Value = valueStr;
Update(obj);
}
else
{
obj = new Setting
{
Name = key,
Value = valueStr
};
Insert(obj);
}
}
}
}
由于需要用到泛型约束,所以要求设置类必须实现接口ISettings
EF映射类:
public class SettingMap : EntityTypeConfiguration<Setting>
{
public SettingMap()
{
this.ToTable("Setting");
this.HasKey(s => s.Id);
this.Property(s => s.Name).HasMaxLength();
}
}
基础设置类:
/// <summary>
/// 基础设置
/// </summary>
public class BaseSetting : ISettings
{
[DisplayName("网站名称")]
public string SiteName { get; set; }
[DisplayName("备案号")]
public string SiteICP { get; set; }
[DisplayName("联系方式")]
public string SiteTel { get; set; }
[DisplayName("版权信息")]
public string Copyright { get; set; }
[DisplayName("状态")]
public bool Status { get; set; }
[DisplayName("缓存时间")]
public int CacheTime { get; set; }
}
在控制器中如下:
public class SettingController : Controller
{
SettingContext settingContext = new SettingContext();
// GET: Setting
public ActionResult Index()
{
return View();
} public ActionResult Base()
{
var setting = settingContext.LoadSetting<BaseSetting>();
return View(setting);
}
[HttpPost]
public ActionResult Base(BaseSetting model)
{
if (ModelState.IsValid)
{
settingContext.SaveSetting<BaseSetting>(model);
}
return View(model);
}
}
视图代码(其实使用了Edit视图基架):

@model SettingDemo.Models.BaseSetting
@{
ViewBag.Title = "Base";
}
<h2>Base</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>BaseSetting</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.SiteName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.SiteName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.SiteName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.SiteICP, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.SiteICP, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.SiteICP, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.SiteTel, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.SiteTel, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.SiteTel, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Copyright, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Copyright, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Copyright, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Status, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
@Html.EditorFor(model => model.Status)
@Html.ValidationMessageFor(model => model.Status, "", new { @class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.CacheTime, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.CacheTime, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.CacheTime, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
浏览前台:

填写设置,保存,查看数据库


这里设置项使用的是类名.属性名,也可以使用完全名称(完全命名空间.类名.属性名),只需适当修改代码即可。扩展自己的设置类需要类似BaseSetting那样,实现接口ISettings。
参考资料:nopcommerce商城系统
ASP.NET MVC实现通用设置的更多相关文章
- asp.net mvc 简易通用自定义Pager实现分页
asp.net mvc 自定义Pager实现分页 Intro 一个WEB应用程序中经常会用到数据分页,本文将实现一个简单通用的分页组件,包含一个 PagerModel (用来保存页码信息),一个 Ht ...
- 给Asp.net MVC Forms 验证设置角色访问控制
当我们使用Asp.net MVC Forms方式验证用户, 然后设置Controller 或 Action 的 Authorize属性时, 默认情况下只有Users属性可以设置(这里的Users通常是 ...
- asp.net错误页和asp.net mvc错误页设置
asp.net错误页 在日常项目开发过程中,我们需要给网站设置错误页和记录错误日志. 首先,在项目中添加全局应用程序类 在Global.asax中 protected void Application ...
- ASP.NET MVC Html.BeginForm 设置 timeout
示例代码: @using (Html.BeginForm("PublishSubmit", "Blog", FormMethod.Post, new { id ...
- ASP.NET MVC为字段设置多语言显示 [转]
这段时间一直在忙.NET的项目,今天就写一下关于.NET的文章吧,也很长时间没写过.NET的啦 在使用ASP.NET MVC3 的时候,使用元数据模式可以非常方便地设置每个 字段(或者说属性)以减少 ...
- ASP.NET MVC EXTJS 通用主菜单框架
一.说明 首先我不知道定义的文章标题是不是准确,我这篇博文介绍的是一个通用的软件主菜单框架,界面布局用的是extjs,还是先上一个图吧. 软件主界面左侧菜单采用的风格是extjs的手风琴模式,需要注意 ...
- AngularJS 初印象------对比 Asp.net MVC
之前就早耳闻前端MVC的一些框架,微软自家的Knockout.js,google家的AngularJs,还有Backone.但未曾了解,也不解为什么前端也要这么分.这两天看了AngularJs的官方教 ...
- 使用Donut Caching和Donut Hole Caching在ASP.NET MVC应用中缓存页面
Donut Caching是缓存除了部分内容以外的整个页面的最好的方式,在它出现之前,我们使用"输出缓存"来缓存整个页面. 何时使用Donut Caching 假设你有一个应用程序 ...
- AngularJS and Asp.net MVC
AngularJS 初印象------对比 Asp.net MVC 之前就早耳闻前端MVC的一些框架,微软自家的Knockout.js,google家的AngularJs,还有Backone.但未曾了 ...
随机推荐
- 面试题43:计算多少种译码方式(decode-ways)
这道题是非常典型的DP问题.按照DP的套路,关键是讨论出递推表达式,遍历过程中针对当前字符是否为'0'以及前一个字符为'0',分类讨论得出到目前字符为止最多有多少种译码方式?理清了递推表达式,代码是很 ...
- Koa2实用入门
koa2已发布了一段时间,可以考虑入手,参见Node.js最新Web技术栈(2016年4月) 本文主要是koa 2的文档解读和runkoa介绍,让大家对koa 2有一个更简单直接的理解 一.依赖Nod ...
- Ruby语言学习系列--String 类函数
函数名称 说明 示例 * 将字符串拷贝N次 “ha”*4 >> “hahahaha” + << concat 连接字符串 “yes” + “no” >& ...
- 基于VUE的SPA单页应用开发-加载性能篇
1.基于异步数据的vue页面刷新 先看看基于异步数据的vue页面刷新后,都发生了啥- 如图所示: 图1 基于异步数据的vue页面刷新 网络请求图 步骤如下: step1:请求页面: step2:请求页 ...
- JavaScript预编译详解
一.js运行三部曲: 1.语法分析(通篇扫描看有没有语法错误) 2.预编译 3.解释执行 二.预编译前奏 1.imply global 暗示全局变量:任何变量如果未经声明就赋值,此变量为全局对象所有 ...
- [Codeforces 993E]Nikita and Order Statistics
Description 题库链接 给你一个长度为 \(n\) 的序列 \(A\) ,和一个数 \(x\) ,对于每个 \(i= 0\sim n\) ,求有多少个非空子区间满足恰好有 \(i\) 个数 ...
- 如何找出长时间未提交的事务session ID
收到报警某台mysql数据库慢查询数量超过5,登录上去看,发现阻塞的SQL全部是update,处于Updating状态 +---------+------+-----------+------+--- ...
- C# 进程间共享内存通信方式
从别处看到一篇文章做进程间通信很好使,唯一的问题是,需要注意using的用法,Using有个用法3, using 语句允许程序员指定使用资源的对象应当何时释放资源.using 语句中使用的对象必须实现 ...
- [HTML5] Canvas绘制简单形状
使用canvas来进行绘画,它像很多其他dom对象一样,有很多属性和方法,操作这些方法,实现绘画 获取canvas对象,调用document.getElementById()方法 调用canvas对象 ...
- PHP · MySQL函数
连接名=mysql_connect("主机","用户名","密码"); 连接名=mysql_qconnect("主机", ...