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; }
    }
View Code

这里是使用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 > 0)
            {
                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);
                }
            }
        }
    }
View Code

由于需要用到泛型约束,所以要求设置类必须实现接口ISettings

EF映射类:

public class SettingMap : EntityTypeConfiguration<Setting>
    {
        public SettingMap()
        {
            this.ToTable("Setting");
            this.HasKey(s => s.Id);
            this.Property(s => s.Name).HasMaxLength(512);
        }
    }
View Code

基础设置类:

/// <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; }
    }
View Code

在控制器中如下:

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);
        }
    }
View Code

视图代码(其实使用了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")
}
View Code

浏览前台:

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

这里设置项使用的是类名.属性名,也可以使用完全名称(完全命名空间.类名.属性名),只需适当修改代码即可。扩展自己的设置类需要类似BaseSetting那样,实现接口ISettings。

参考资料:nopcommerce商城系统

posted @ 2017-09-07 23:47  Jichan·Jong  阅读(932)  评论(0编辑  收藏  举报