zoukankan      html  css  js  c++  java
  • MVC中使用T4模板

    参考博文

    http://www.cnblogs.com/heyuquan/archive/2012/07/26/2610959.html

    图片释义

    1、简单示例,对基本的模块标记

    2、根据上图生成的类

    网上大佬写的JuCheap项目中的T4模板

    https://gitee.com/jucheap/projects

    T4代码

    <#@ template  language="C#"    debug="true" hostspecific="True"#> 
    <#@ include file="$(SolutionDir)JuCheap.ServiceMultipleOutputHelper.ttinclude" #>
    <#@ import namespace="System"#>
    
    <#
        string solutionsPath = Host.ResolveAssemblyReference("$(SolutionDir)");
        var files = System.IO.Directory.GetFiles(solutionsPath + @"JuCheap.Entity", "*.cs");
    
        var manager = Manager.Create(Host, GenerationEnvironment);
    
        //1.开始输出接口契约文件
        foreach (var filePath in files)
        {
            var file = new FileInfo(filePath);
            var name = file.Name.Replace("Entity.cs",string.Empty);
            var lowerName =name.ToLower();
            //定义输出文件
            manager.StartNewFile("I"+name+"Service.Partial.cs", string.Empty);
    #>
    
    /*******************************************************************************
    * Copyright (C)  JuCheap.Com
    * 
    * Author: dj.wong
    * Create Date: <#=DateTime.Now#>
    * Description: Automated building by service@JuCheap.com 
    * 
    * Revision History:
    * Date         Author               Description
    * 2017-08-02   dj.wong              optimization
    *********************************************************************************/
    
    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using JuCheap.Service.Dto;
    
    namespace JuCheap.Service.Abstracts
    { 
        /// <summary>
        /// <#=name#>业务契约
        /// </summary>
        public partial interface I<#=name#>Service
        {
            /// <summary>
            /// 添加<#=lowerName#>
            /// </summary>
            /// <param name="<#=lowerName#>"><#=lowerName#>实体</param>
            /// <returns></returns>
            bool Add(<#=name#>Dto <#=lowerName#>);
    
            /// <summary>
            /// 批量添加<#=lowerName#>
            /// </summary>
            /// <param name="models"><#=lowerName#>集合</param>
            /// <returns></returns>
            bool Add(List<<#=name#>Dto> models);
    
            /// <summary>
            /// 编辑<#=lowerName#>
            /// </summary>
            /// <param name="<#=lowerName#>">实体</param>
            /// <returns></returns>
            bool Update(<#=name#>Dto <#=lowerName#>);
    
            /// <summary>
            /// 批量更新<#=lowerName#>
            /// </summary>
            /// <param name="<#=lowerName#>s"><#=lowerName#>实体集合</param>
            /// <returns></returns>
            bool Update(IEnumerable<<#=name#>Dto> <#=lowerName#>s);
    
            /// <summary>
            /// 删除<#=lowerName#>
            /// </summary>
            /// <param name="id">Id</param>
            /// <returns></returns>
            bool Delete(int id);
    
            /// <summary>
            /// 批量删除<#=lowerName#>
            /// </summary>
            /// <param name="exp">条件表达式</param>
            /// <returns></returns>
            bool Delete(Expression<Func<<#=name#>Dto, bool>> exp);
    
            /// <summary>
            ///  获取单条符合条件的 <#=lowerName#> 数据
            /// </summary>
            /// <param name="exp">条件表达式</param>
            /// <returns></returns>
            <#=name#>Dto GetOne(Expression<Func<<#=name#>Dto, bool>> exp);
    
            /// <summary>
            /// 查询符合调价的 <#=lowerName#>
            /// </summary>
            /// <param name="exp">过滤条件</param>
            /// <param name="orderExp">排序条件</param>
            /// <param name="isDesc">是否是降序排列</param>
            /// <returns></returns>
            List<<#=name#>Dto> Query<OrderKeyType>(Expression<Func<<#=name#>Dto, bool>> exp, Expression<Func<<#=name#>Dto, OrderKeyType>> orderExp, bool isDesc = true);
    
            /// <summary>
            /// 分页获取<#=lowerName#>
            /// </summary>
            /// <param name="queryBase">QueryBase</param>
            /// <param name="exp">过滤条件</param>
            /// <param name="orderExp">排序条件</param>
            /// <param name="isDesc">是否是降序排列</param>
            /// <returns></returns>
            ResultDto<<#=name#>Dto> GetWithPages<OrderKeyType>(QueryBase queryBase, Expression<Func<<#=name#>Dto, bool>> exp, Expression<Func<<#=name#>Dto, OrderKeyType>> orderExp, bool isDesc = true);
    
            /// <summary>
            /// 分页获取<#=lowerName#>
            /// </summary>
            /// <param name="queryBase">QueryBase</param>
            /// <param name="exp">过滤条件</param>
            /// <param name="orderBy">排序条件</param>
            /// <param name="orderDir">是否是降序排列</param>
            /// <returns></returns>
            ResultDto<<#=name#>Dto> GetWithPages(QueryBase queryBase, Expression<Func<<#=name#>Dto, bool>> exp, string orderBy, string orderDir = "desc");
        } 
    }
    <# 
        // 结束输出文件
        manager.EndBlock();
    } 
        //2.开始生成契约实现文件
        foreach (var filePath in files)
        {
            var file = new FileInfo(filePath);
            var name = file.Name.Replace("Entity.cs",string.Empty);
            var lowerName = name.ToLower();
            //定义输出文件
            manager.StartNewFile(name+"Service.Partial.cs", string.Empty);
    #>
    
    /*******************************************************************************
    * Copyright (C)  JuCheap.Com
    * 
    * Author: dj.wong
    * Create Date: <#=DateTime.Now#>
    * Description: Automated building by service@JuCheap.com 
    * 
    * Revision History:
    * Date         Author               Description
    *
    *********************************************************************************/
    
    using System;
    using System.Collections.Generic;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using System.Linq.Expressions;
    using EntityFramework.Extensions;
    using AutoMapper;
    using JuCheap.Core;
    using JuCheap.Core.Extentions;
    using JuCheap.Entity;
    using JuCheap.Service.Dto;
    using Mehdime.Entity;
    
    namespace JuCheap.Service.Abstracts
    { 
        /// <summary>
        /// <#=name#>业务契约
        /// </summary>
        public partial class <#=name#>Service : ServiceBase<<#=name#>Entity>, IDependency, I<#=name#>Service
        {
            #region 构造函数注册上下文
            public IDbContextScopeFactory _dbScopeFactory {get;set;}
    
            //private readonly IDbContextScopeFactory _dbScopeFactory;
    
            //public <#=name#>Service(IDbContextScopeFactory dbScopeFactory)
            //{
            //    _dbScopeFactory = dbScopeFactory;
            //}
    
            #endregion
    
            #region I<#=name#>Service 接口实现
    
            /// <summary>
            /// 添加<#=lowerName#>
            /// </summary>
            /// <param name="dto"><#=lowerName#>实体</param>
            /// <returns></returns>
            public bool Add(<#=name#>Dto dto)
            {
                using (var scope = _dbScopeFactory.Create())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var entity = Mapper.Map<<#=name#>Dto, <#=name#>Entity>(dto);
                    dbSet.Add(entity);
                    var count = db.SaveChanges();
                    return count > 0;
                }
            }
    
            /// <summary>
            /// 批量添加<#=lowerName#>
            /// </summary>
            /// <param name="dtos"><#=lowerName#>集合</param>
            /// <returns></returns>
            public bool Add(List<<#=name#>Dto> dtos)
            {
                using (var scope = _dbScopeFactory.Create())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var entities = Mapper.Map<List<<#=name#>Dto>, List<<#=name#>Entity>>(dtos);
                    dbSet.AddRange(entities);
                    return db.SaveChanges() > 0;
                }
            }
    
            /// <summary>
            /// 编辑<#=lowerName#>
            /// </summary>
            /// <param name="dto">实体</param>
            /// <returns></returns>
            public bool Update(<#=name#>Dto dto)
            {
                using (var scope = _dbScopeFactory.Create())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var entity = Mapper.Map<<#=name#>Dto, <#=name#>Entity>(dto);
                    dbSet.AddOrUpdate(entity);
                    return db.SaveChanges() > 0;
                }
            }
    
            /// <summary>
            /// 批量更新<#=lowerName#>
            /// </summary>
            /// <param name="dtos"><#=lowerName#>实体集合</param>
            /// <returns></returns>
            public bool Update(IEnumerable<<#=name#>Dto> dtos)
            {
                using (var scope = _dbScopeFactory.Create())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var entities = Mapper.Map<IEnumerable<<#=name#>Dto>, IEnumerable<<#=name#>Entity>>(dtos);
                    dbSet.AddOrUpdate(entities.ToArray());
                    return db.SaveChanges() > 0;
                }
            }
    
            /// <summary>
            /// 删除<#=lowerName#>
            /// </summary>
            /// <param name="id">Id</param>
            /// <returns></returns>
            public bool Delete(int id)
            {
                using (var scope = _dbScopeFactory.Create())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
    
                    var model = dbSet.FirstOrDefault(item => item.Id == id);
                    dbSet.Remove(model);
                    return db.SaveChanges() > 0;
                }
            }
    
            /// <summary>
            /// 批量删除<#=lowerName#>
            /// </summary>
            /// <param name="exp">条件表达式</param>
            /// <returns></returns>
            public bool Delete(Expression<Func<<#=name#>Dto, bool>> exp)
            {
                using (var scope = _dbScopeFactory.Create())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var where = exp.Cast<<#=name#>Dto, <#=name#>Entity, bool>();
                    
                    var models = dbSet.Where(where);
                    dbSet.RemoveRange(models);
                    return db.SaveChanges() > 0;
                }
            }
    
            /// <summary>
            ///  获取单条符合条件的 <#=lowerName#> 数据
            /// </summary>
            /// <param name="exp">条件表达式</param>
            /// <returns></returns>
            public <#=name#>Dto GetOne(Expression<Func<<#=name#>Dto, bool>> exp)
            {
                using (var scope = _dbScopeFactory.CreateReadOnly())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var where = exp.Cast<<#=name#>Dto, <#=name#>Entity, bool>();
                    var entity = dbSet.AsNoTracking().FirstOrDefault(where);
    
                    return Mapper.Map<<#=name#>Entity, <#=name#>Dto>(entity);
                }
            }
    
            /// <summary>
            /// 查询符合调价的 <#=lowerName#>
            /// </summary>
            /// <param name="exp">过滤条件</param>
            /// <param name="orderExp">排序条件</param>
            /// <param name="isDesc">是否是降序排列</param>
            /// <returns></returns>
            public List<<#=name#>Dto> Query<OrderKeyType>(Expression<Func<<#=name#>Dto, bool>> exp, Expression<Func<<#=name#>Dto, OrderKeyType>> orderExp, bool isDesc = true)
            {
                using (var scope = _dbScopeFactory.CreateReadOnly())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var where = exp.Cast<<#=name#>Dto, <#=name#>Entity, bool>();
                    var order = orderExp.Cast<<#=name#>Dto, <#=name#>Entity, OrderKeyType>();
                    var query = GetQuery(dbSet, where, order, isDesc);
                    var list = query.ToList();
                    return Mapper.Map<List<<#=name#>Entity>, List<<#=name#>Dto>>(list);
                }
            }
    
            /// <summary>
            /// 分页获取<#=name#>
            /// </summary>
            /// <param name="queryBase">QueryBase</param>
            /// <param name="exp">过滤条件</param>
            /// <param name="orderExp">排序条件</param>
            /// <param name="isDesc">是否是降序排列</param>
            /// <returns></returns>
            public ResultDto<<#=name#>Dto> GetWithPages<OrderKeyType>(QueryBase queryBase, Expression<Func<<#=name#>Dto, bool>> exp, Expression<Func<<#=name#>Dto, OrderKeyType>> orderExp, bool isDesc = true)
            {
                using (var scope = _dbScopeFactory.CreateReadOnly())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var where = exp.Cast<<#=name#>Dto, <#=name#>Entity, bool>();
                    var order = orderExp.Cast<<#=name#>Dto, <#=name#>Entity, OrderKeyType>();
                    var query = GetQuery(dbSet, where, order, isDesc);
    
                    var query_count = query.FutureCount();
                    var query_list = query.Skip(queryBase.Start).Take(queryBase.Length).Future();
                    var list = query_list.ToList();
    
                    var dto = new ResultDto<<#=name#>Dto>
                    {
                        recordsTotal = query_count.Value,
                        data = Mapper.Map<List<<#=name#>Entity>, List<<#=name#>Dto>>(list)
                    };
                    return dto;
                }
            }
    
            /// <summary>
            /// 分页获取<#=name#>
            /// </summary>
            /// <param name="queryBase">QueryBase</param>
            /// <param name="exp">过滤条件</param>
            /// <param name="orderBy">排序条件</param>
            /// <param name="orderDir">排序类型:desc(默认)/asc</param>
            /// <returns></returns>
            public ResultDto<<#=name#>Dto> GetWithPages(QueryBase queryBase, Expression<Func<<#=name#>Dto, bool>> exp, string orderBy, string orderDir = "desc")
            {
                using (var scope = _dbScopeFactory.CreateReadOnly())
                {
                    var db = GetDb(scope);
                    var dbSet = GetDbSet(db);
                    var where = exp.Cast<<#=name#>Dto, <#=name#>Entity, bool>();
                    //var order = orderExp.Cast<<#=name#>Dto, <#=name#>Entity, OrderKeyType>();
                    var query = GetQuery(dbSet, where, orderBy, orderDir);
    
                    var query_count = query.FutureCount();
                    var query_list = query.Skip(queryBase.Start).Take(queryBase.Length).Future();
                    var list = query_list.ToList();
    
                    var dto = new ResultDto<<#=name#>Dto>
                    {
                        recordsTotal = query_count.Value,
                        data = Mapper.Map<List<<#=name#>Entity>, List<<#=name#>Dto>>(list)
                    };
                    return dto;
                }
            }
    
            #endregion
        } 
    }
    <# 
        // 结束输出文件
        manager.EndBlock();
    }
    #> 
    
    
    <#
        manager.StartNewFile("AutoMapperConfiguration.Partial.cs", string.Empty);
    #>
    
    
    /*******************************************************************************
    * Copyright (C)  JuCheap.Com
    * 
    * Author: dj.wong
    * Create Date: 2015/8/7 11:12:12
    * Description: Automated building by service@JuCheap.com 
    * 
    * Revision History:
    * Date         Author               Description
    *
    *********************************************************************************/
    
    using AutoMapper;
    using JuCheap.Entity;
    using JuCheap.Service.Dto;
    
    namespace JuCheap.Service
    {
        /// <summary>
        /// AutoMapper 配置
        /// </summary>
        public partial class AutoMapperConfiguration
        {
            /// <summary>
            /// 配置AutoMapper
            /// </summary>
            public static void Config()
            {
    <#
        //1.开始输出接口契约文件
        foreach (var filePath in files)
        {
            var file = new FileInfo(filePath);
            var name = file.Name.Replace("Entity.cs",string.Empty);
            var lowerName =name.ToLower();
            //定义输出文件
    #>
                Mapper.CreateMap<<#=name#>Entity, <#=name#>Dto>();
                Mapper.CreateMap<<#=name#>Dto, <#=name#>Entity>();
    <# 
        }
    #>
            }
        }
    }
    <#
        // 结束输出文件
        manager.EndBlock();
        // 执行编译
        manager.Process(true);  
    #> 

    引用的ttInclude代码

    <#@ assembly name="System.Core"
    #><#@ assembly name="System.Data.Linq"
    #><#@ assembly name="EnvDTE"
    #><#@ assembly name="System.Xml"
    #><#@ assembly name="System.Xml.Linq"
    #><#@ import namespace="System.Collections.Generic"
    #><#@ import namespace="System.IO"
    #><#@ import namespace="System.Text"
    #><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
    #><#+
    // https://raw.github.com/damieng/DamienGKit
    // http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited
    // Manager class records the various blocks so it can split them up
    class Manager {
        private class Block {
            public String Name;
            public string FilePath;
            public int Start, Length;
            public bool IncludeInDefault;
        }
    
        private Block currentBlock;
        private readonly List<Block> files = new List<Block>();
        private readonly Block footer = new Block();
        private readonly Block header = new Block();
        private readonly ITextTemplatingEngineHost host;
        private readonly StringBuilder template;
        protected readonly List<String> generatedFileNames = new List<String>();
    
        public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
            return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
        }
    
        public void StartNewFile(String name, string filePath) {
            if (name == null)
                throw new ArgumentNullException("name");
            CurrentBlock = new Block { Name = name, FilePath = filePath };
        }
    
        public void StartFooter(bool includeInDefault = true) {
            CurrentBlock = footer;
            footer.IncludeInDefault = includeInDefault;
        }
    
        public void StartHeader(bool includeInDefault = true) {
            CurrentBlock = header;
            header.IncludeInDefault = includeInDefault;
        }
    
        public void EndBlock() {
            if (CurrentBlock == null)
                return;
            CurrentBlock.Length = template.Length - CurrentBlock.Start;
            if (CurrentBlock != header && CurrentBlock != footer)
                files.Add(CurrentBlock);
            currentBlock = null;
        }
    
        public virtual void Process(bool split, bool sync = true) {
            if (split) {
                EndBlock();
                String headerText = template.ToString(header.Start, header.Length);
                String footerText = template.ToString(footer.Start, footer.Length);
                String outputPath = Path.GetDirectoryName(host.TemplateFile);
                files.Reverse();
                if (!footer.IncludeInDefault)
                    template.Remove(footer.Start, footer.Length);
                foreach(Block block in files) {
                    String myPath = block.FilePath;
                    if(!string.IsNullOrWhiteSpace(myPath))
                        outputPath = myPath;
                    String fileName = Path.Combine(outputPath, block.Name);
                    String content = headerText + template.ToString(block.Start, block.Length) + footerText;
                    generatedFileNames.Add(fileName);
                    CreateFile(fileName, content);
                    template.Remove(block.Start, block.Length);
                }
                if (!header.IncludeInDefault)
                    template.Remove(header.Start, header.Length);
            }
        }
    
        protected virtual void CreateFile(String fileName, String content) {
            if (IsFileContentDifferent(fileName, content))
                File.WriteAllText(fileName, content);
        }
    
        public virtual String GetCustomToolNamespace(String fileName) {
            return null;
        }
    
        public virtual String DefaultProjectNamespace {
            get { return null; }
        }
    
        protected bool IsFileContentDifferent(String fileName, String newContent) {
            return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
        }
    
        private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
            this.host = host;
            this.template = template;
        }
    
        private Block CurrentBlock {
            get { return currentBlock; }
            set {
                if (CurrentBlock != null)
                    EndBlock();
                if (value != null)
                    value.Start = template.Length;
                currentBlock = value;
            }
        }
    
        private class VSManager: Manager {
            private readonly EnvDTE.ProjectItem templateProjectItem;
            private readonly EnvDTE.DTE dte;
            private readonly Action<String> checkOutAction;
            private readonly Action<List<String>> projectSyncAction;
    
            public override String DefaultProjectNamespace {
                get {
                    return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
                }
            }
    
            public override String GetCustomToolNamespace(string fileName) {
                return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
            }
    
            public override void Process(bool split, bool sync) {
                if (templateProjectItem.ProjectItems == null)
                    return;
                base.Process(split, sync);
                if (sync)
                    projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
            }
    
            protected override void CreateFile(String fileName, String content) {
                if (IsFileContentDifferent(fileName, content)) {
                    CheckoutFileIfRequired(fileName);
                    File.WriteAllText(fileName, content);
                }
            }
    
            internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
                : base(host, template) {
                var hostServiceProvider = (IServiceProvider)host;
                if (hostServiceProvider == null)
                    throw new ArgumentNullException("Could not obtain IServiceProvider");
                dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
                if (dte == null)
                    throw new ArgumentNullException("Could not obtain DTE from host");
                templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
                checkOutAction = fileName => dte.SourceControl.CheckOutItem(fileName);
                projectSyncAction = keepFileNames => ProjectSync(templateProjectItem, keepFileNames);
            }
    
            private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, List<String> keepFileNames) {
                var keepFileNameSet = new HashSet<String>(keepFileNames);
                var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
                var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.FileNames[0]) + ".";
                foreach (EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
                    projectFiles.Add(projectItem.FileNames[0], projectItem);
    
                // Remove unused items from the project
                foreach (var pair in projectFiles)
                    if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
                        pair.Value.Delete();
    
                // Add missing files to the project
                foreach(String fileName in keepFileNameSet)
                    if (!projectFiles.ContainsKey(fileName))
                        templateProjectItem.ProjectItems.AddFromFile(fileName);
            }
    
            private void CheckoutFileIfRequired(String fileName) {
                var sc = dte.SourceControl;
                if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
                    checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
            }
        }
    } #>

    用到的语法:

    1、string solutionsPath = Host.ResolveAssemblyReference("$(SolutionDir)");

    T4模板中获取当前解决方案的文件路径。

    2、var files = System.IO.Directory.GetFiles(solutionsPath + @"JuCheap.Entity", "*.cs");

    获取JuCheap.Entity项目中所有cs扩展名的文件信息。

     3、var manager = Manager.Create(Host, GenerationEnvironment);

    在引用的ttInclude中,创建一个模板管理者的对象,用于操作和生成数据。

    4、 public partial interface I<#=name#>Service

    在<#  string name="ClassName" #> 中声明的变量,

    可以在文本块中以<#=name#>的形式调用。(name为声明的变量名称)

    5、 manager.EndBlock();

    在引用的ttInclude中,结束对新服务类的内容赋值,

    将文件对象添加到文件集合中。

    6、manager.Process(true); 

    在引用的ttInclude中,结束数据生成,编译运行,生成相应的文件。

    总结

    因为有CodeSmith的使用经验,所以在看到T4模板使用方法时,

    没有想象的那么困难。

    纸上得来终觉浅,绝知此事要躬行。

    目前只是看网上大佬的教程,还没有在项目中实际使用过,

    还有许多未知的问题和操作。

  • 相关阅读:
    帝国 标签模板 使用程序代码 去除html标记 并 截取字符串
    iis6 伪静态 iis配置方法 【图解】
    您来自的链接不存在 帝国CMS
    帝国cms Warning: Cannot modify header information headers already sent by...错误【解决方法】
    .fr域名注册 51元注册.fr域名
    帝国网站管理系统 恢复栏目目录 建立目录不成功!请检查目录权限 Godaddy Windows 主机
    星外虚拟主机管理平台 开通数据库 出现Microsoft OLE DB Provider for SQL Server 错误 '8004' 从字符串向 datetime 转换失败
    ASP.NET 自定义控件学习研究
    CSS层叠样式表之CSS解析机制的优先级
    ASP.NET程序员工作面试网络收藏夹
  • 原文地址:https://www.cnblogs.com/masonblog/p/9233178.html
Copyright © 2011-2022 走看看