我需要创建一个Book 新葡京32450网址:Type的Matter,前面的书房初始化的前端信息已经完善

发布时间:2019-11-05  栏目:数据  评论:0 Comments

 1     using M = Shelf;
 2     public class InitModel : PageModel
 3     {
 4         private readonly IShelfRepo _shelfRepo;
 5         public InitModel(IShelfRepo shelfRepo)
 6         {
 7             _shelfRepo = shelfRepo;
 8         }
 9         [BindProperty]
10         public InitInputModel Input { get; set; }
11 
12         public void OnGet()
13         {
14 
15         }
16 
17         public async Task<IActionResult> OnPostAsync()
18         {
19             if (ModelState.IsValid)
20             {
21                 await _shelfRepo.InitAsync(new M.InitSpec
22                 {
23                     NickName = Input.NickName.Trim(),
24                     ShelfName = Input.ShelfName.Trim()
25                 });
26                 return RedirectToPage("New");
27             }
28             return Page();
29         }
30     }

继续,插入BookSupplement信息;


    def open_conn(self):
        """连接数据库,并建立游标"""
        try:
            if not self.connect:
                self.connect = psycopg2.connect(database=self.db_name, user=self.db_user, password=self.db_pass, host=self.db_host, port=self.db_port)
            return self.connect
        except Exception as e:
            log_helper.error('连接数据库失败:' + str(e.args))
            return False

    def close_conn(self):
        """关闭postgresql数据库链接"""
        # 关闭游标
        try:
            if self.cursor:
                self.cursor.close()
        except Exception:
            pass
        # 关闭数据库链接
        try:
            if self.connect:
                self.connect.close()
        except Exception:
            pass

新葡京32450网址 1

 

下面要做的是展示Shelf中的Book信息,要等今天活干完才能继续写了。

优化入口文件

  首先我们需要将配置独立出来,当有需要链接多个数据库时,可以读取不同的配置文件,让程序更加方便灵活。

在很多的教材和案例中,MVC验证都是通过提交表单进行的。通过提交表单,可以很容易获得验证出错信息。因为,无论是客户端验证还是服务端验证,总能找到与Model属性或验证特性对应的html元素和属性,并把错误信息显示出来。可是,在实际项目中,经常会遇到需要异步提交的情况。那么,如何把服务端的验证错误信息传递给前端视图呢?

在测试之前,我们需要实现一下Init Razor Pages代码:

继续,插入BookInfo的信息;

上一篇中,提出4个问题待解决,本篇集中解决这4个问题,最终形成完整的微型MVC框架结构,
后续博客项目,或其他项目,均可以直接使用该框架结构进行开发学习。

  通过对代码的简单分析,可以看到整个模块在初化时,载入数据库链接配置,对数据库的操作也只有简单读与写操作。这样的功能对于一般的数据库增删改查操作已经足够了,但如果业务复杂,有多个库、需要用到事务或者需要访问不同类型数据库时,它就不够用了。所以首先要做的就是对它进行重构,功能进行完善。

新葡京32450网址 2

 1 CREATE PROCEDURE [svc].[Shelf$Init](@json nvarchar(max))
 2 WITH ENCRYPTION
 3 AS
 4 BEGIN
 5     SET    NOCOUNT    ON;
 6     SET XACT_ABORT ON;
 7     BEGIN TRY
 8         BEGIN    TRAN;
 9 
10         declare    @nickName nvarchar(20), @shelfName nvarchar(20);
11         select    @nickName=NickName,     @shelfName=ShelfName
12         from    openjson (@json, '$')
13         with (
14             NickName        nvarchar(20),
15             ShelfName        nvarchar(20)
16         );
17 
18         insert    core._Party(Type, Alias) select k._User, @nickName
19         from    core.Party#Type() k;
20         declare    @userID int=@@identity;
21 
22         
23         insert    core._Party(PID, Type, Alias) select @userID, k._Shelf, @shelfName
24         from    core.Party#Type() k;
25 
26         COMMIT    TRAN;
27     END TRY
28     BEGIN CATCH
29         if (xact_state() = -1) ROLLBACK TRAN; throw;
30     END CATCH
31 END

首先,我需要创建一个Book Type的Matter;

小结:

主要实现了 引入路径优化, 类的自动加载, 封装优化入口文件,目录访问限制

MVC微型框架到此基本完成。其实还有很多还是可以继续扩展,如

  1, 类文件命名此处都用了 .class.php结尾,
实质可以优化直接使用.php结尾

  2, 引入命名空间,更方便的加载类

3, 项目中出现错误,此时是直接显示在浏览器上的,
可以写一个日志类,发生错误写入文件或数据库都可

  4, 数据库连接信息此处是直接写在DB类和BaseModel中了, 是不安全的。
可以创建一个配置目录,将这些信息写入配置文件,再写一个加载配置文件的类。

  5. 此架构目录 ,是在C,V中分平台,如Controller/Home,
Controller/Admin; 实际也可以写成 平台下分MVC结构, 如Admin/Controller,
Admin/Model, Home/Controller,Home/View ..
这个是比较灵活的,可以根据需求选择更加合适的方式

  实际上线项目,还是建议使用框架,安全快捷;
自己模仿定义的框架结构适合学习研究使用,容易遗漏,造成安全隐患,操作不便等问题

下一步:根据博客前端模板,分析创建数据表,
开始搭建博客后台程序,后续首先准备实现
“分类模块”。既分类的展示,修改,添加,删除功能

    def __enter__(self):
        """初始化数据库链接"""
        self.open_conn()
        return self

    def __exit__(self, type, value, trace):
        """关闭postgresql数据库链接"""
        self.close_conn()

本文主要体验通过jQuery异步验证。

Init.cshtml.cs

继续,插入BookTranslator信息;

安全访问项目目录

 

  • key).html(value[value.length – 1].ErrorMessage)。
1 CREATE SCHEMA [svc]
2     AUTHORIZATION [dbo];

继续,插入Book信息;

  代码实现

1)操作步骤

新葡京32450网址 3新葡京32450网址 4

step 1: 在入口文件中定义所需要的常量step 2: 控制器中引入视图时, 使用常量进行优化 

操作步骤思路

2) 入口文件中定义常用路径常量 【index.php】

 1 <?php 2 /** 3  * 入口文件 4  */ 5 $p = !empty($_GET['p']) ? $_GET['p'] : 'Home';  //平台 6 $c = !empty($_GET['c']) ? $_GET['c'] : 'User';  //控制器 7 $a = !empty($_GET['a']) ? $_GET['a'] : 'login'; //动作 8  9 define('PLAT', $p);  //平台常量10 define('CTR', $c);  //控制器11 define('ACTION', $a); //动作12 13 14 define('DS', DIRECTORY_SEPARATOR); //目录分割符15 define('ROOT', getcwd;  //当前所在目录 项目目录16 define('FRAME', ROOT.'Frame'.DS);17 define('APP', ROOT.'App'.DS);18 define('PUB', ROOT.'Public'.DS);19 define('ADMIN', PUB.'Admin'.DS);20 define('HOME', PUB.'Home'.DS);21 22 //MVC目录23 define('MODEL', APP.'Model'.DS);24 define('VIEW', APP.'View'.DS.PLAT.DS.CTR.DS);25 define('CTRONLLER', APP.'Controller'.DS.PLAT.DS);26 27 $ctr = $c."Controller";28 29 require_once FRAME.'Db.class.php';  //数据库操作类30 require_once FRAME.'BaseModel.class.php';  //基础模型类31 require_once MODEL.'UserModel.class.php';  //用户模型类32 require_once FRAME.'FactoryModel.class.php';//模型工厂类33 require_once FRAME.'BaseController.class.php'; //基础控制器类34 require_once CTRONLLER.$ctr.'.class.php';35 36 37 //实例化控制器38 $userCtr = new $ctr();39 40 $userCtr -> $a();

2) 常量的使用:

  后台首页控制器【App/Controller/Admin/IndexController.class.php】

新葡京32450网址 5新葡京32450网址 6

 1 <?php 2 /** 3  * IndexController控制器类 4  * 后台相关操作 5  * User: young 6  */ 7  8 class IndexController extends BaseController 9 {10     //展示后台首页11     public function index()12     {13         include VIEW.'index.html';14     }15 }

后台首页控制器引入视图路径修改

  用户控制器
登录视图引入路径【App/Controller/Home/UserController.class.php】

新葡京32450网址 7新葡京32450网址 8

 1 <?php 2 /** 3  * UserController.class.php 用户控制器 4  */ 5  6 class UserController  extends  BaseController{ 7     /** 8      * 展示登录界面 9      * @access public10      */11     public function login()12     {13         include VIEW."login.html";14     }15 。。。16 。。。17 。。。

用户控制器登录视图引入路径

3)提交代码

$  git add -A$  git commit -m "常量使用"

 

填写分数不在定义区间报错:

前面的书房初始化的前端信息已经完善,所以现在开始实现DB的Script部分。

 1 CREATE PROCEDURE [base].[BookTranslator#Insert](@json nvarchar(max), @bookID bigint)
 2 WITH ENCRYPTION
 3 AS
 4 BEGIN
 5 ...
 6 
 7         -- insert Translator
 8         insert    base._Author(Name)select value
 9         from    openjson(@json, '$.Translators') x
10         where    not exists(select 1 from base._Author p where p.Name=x.value);
11 
12         insert    base._BookTranslator(BookID, TranslatorID) select @bookID, x.ID
13         from    openjson(@json, '$.Translators') j join base.Author#Raw() x on x.Name=j.value
14 
15 ...
16 END

  思路

  1)把常用的目录路径定义成常量。如 模型目录,控制器目录等
 2)引入类使用定义的常量替代部分路径。 如 include
FRAME.BaseModel.class.php
3) 载入视图使用常量替代部分路径 如 include VIEW.’login.html’ 简单形式

  4.它需要支持查询、添加、修改、删除等操作,方便我们操作关系型数据库记录(需要创建sql执行方法)

using System;

using System.ComponentModel.DataAnnotations;

 

namespace DataAnnotationAjax.Models

{

    public class Student

    {

        public int Id { get; set; }

 

        [Required(ErrorMessage = "姓名为必填项")]

        [Display(Name = "姓名")]

        public string Name { get; set; }

 

        [Required(ErrorMessage = "分数是必选项")]

        [Range(60, 100, ErrorMessage = "分数必须在60和100之间")]

        [Display(Name = "分数")]

        public int Score { get; set; }

 

        [Display(Name = "招收日期")]

        public DateTime Enrollment { get; set; }

    }

}

新葡京32450网址 9

 

下载查看该项目源码:

新葡京32450网址 10新葡京32450网址 11

  • key)。

svc.sql

继续,插入Binding信息(也需要判断name不存在才insert),返回BindingID;

  代码实现

  1) 在Frame目录中创建Init.class.php文件,
将入口文件index中的代码复制进行修改为类

  【Frame/Init.class.php】

 1 <?php 2 /** 3  * 应用初始化操作类 4  * User: young 5  */ 6  7 class Init 8 { 9     protected static $frame = array('BaseController','BaseModel','Db','FactoryModel'); //Frame目录公共操作类10     public static function run()11     {12         //平台13         self::dispatch();14 15         //定义常量16         self::setConst();17 18         //自动加载类19         self::loadClass();20 21         $ctr = CTR."Controller";  //拼接控制器名称22 23         //实例化控制器24         $ctrObj = new $ctr();25         $a = ACTION;26         $ctrObj -> $a();27     }28     /**29      * 设置自动加载类方法30      */31     private static function loadClass()32     {33         spl_autoload_register('self::autoload');34     }35 36     /**37      * 实现自动加载38      * @param  string $className 类名39      */40     private static function autoload($className)41     {42         $upperClassName = strtoupper($className);43         if(in_array($className, static::$frame)) {44             require_once FRAME."$className.class.php";45         } elseif(substr($upperClassName, -5) == 'MODEL'){46             require_once MODEL."$className.class.php";47         } elseif(substr($upperClassName, -10) == 'CONTROLLER'){48             require_once CTRONLLER."$className.class.php";49         }50     }51 52     /**53      * 定义常量54      */55     private static function setConst()56     {57         define('DS', DIRECTORY_SEPARATOR); //目录分割符58         define('ROOT', getcwd().DS);59         define('FRAME', ROOT.'Frame'.DS);60         define('APP', ROOT.'App'.DS);61         define('PUB', ROOT.'Public'.DS);62         define('ADMIN', PUB.'Admin'.DS);63         define('HOME', PUB.'Home'.DS);64 65 66         define('MODEL', APP.'Model'.DS);67         define('VIEW', APP.'View'.DS.PLAT.DS.CTR.DS);68         define('CTRONLLER', APP.'Controller'.DS.PLAT.DS);69     }70 71     /**72      * 获取 p c a 的GET值,并设置为常量73      * @return void74      */75     private static function dispatch()76     {77         $p = !empty($_GET['p']) ? $_GET['p'] : 'Home';  //平台78         $c = !empty($_GET['c']) ? $_GET['c'] : 'User';  //控制器79         $a = !empty($_GET['a']) ? $_GET['a'] : 'login'; //动作80 81         define('PLAT', $p);82         define('CTR', $c);83         define('ACTION', $a);84     }85 }

2) 入口文件引入初始化类,并调用其方法 【index.php】

1 <?php2 /**3  * 入口文件4  */5 6 require_once './Frame/Init.class.php';7 Init::run();

3) 提交代码

1 $  git add -A2 $  git commit -m "优化入口文件,封装初始化类"

  完成的db_helper.py代码

  View model

填写不动书房的信息:

 1 CREATE PROCEDURE [base].[Binding#Insert](@json nvarchar(max), @id int out)
 2 WITH ENCRYPTION
 3 AS
 4 BEGIN
 5 ...
 6 
 7         declare    @name nvarchar(100);
 8         select    @name=Binding from openjson(@json, '$') with (Binding nvarchar(100))
 9 
10         -- insert Binding
11         insert    base._Binding(Name)select @name
12         where    not exists(select 1 from base._Binding p where p.Name=@name);
13 
14         select    @id=ID from base.Binding#Raw() where Name=@name;
15 
16 ...
17 END
  1. 常量优化路径
  2. 自动加载类
  3. 优化入口文件
  4. 安全访问项目目录

   最后一个是记录超时sql语句到日志方法,这里我将大于0.1秒的sql语句都记录下来

 

 1 <form method="post">
 2     <div class="form-group form-group-lg">
 3         <label asp-for="Input.NickName"></label>
 4         <input class="form-control form-control-lg" asp-for="Input.NickName" autocomplete="off">
 5         
 6     </div>
 7     <div class="form-group form-group-lg">
 8         <label asp-for="Input.ShelfName"></label>
 9         <input class="form-control form-control-lg" asp-for="Input.ShelfName" autocomplete="off">
10         
11     </div>
12     <div class="form-group text-right">
13         <button class="btn btn-warning btn-lg" type="submit">Save</button>
14     </div>
15 </form>

昨晚完成了Web端新增图书信息的功能,现在就差DB的具体实现了。

  思路

  问题:
此时,项目中所有目录都是可以通过浏览器访问的,如直接访问Frame/Db.class.php文件
直接可以去查看数据库登录信息,显然是不安全的。

  解决方法:

    方式1:
在可以访问的文件开始处定义常量,访问是判断是否定义常量defined,
没有定义指定常量则直接exit(‘Access Deny’);

    方式2: 开启分布式权限配置,编写.htaccess文件, 如禁止访问,
将该文件放置在禁止访问的目录中

  1 #!/usr/bin/env python
  2 # coding=utf-8
  3 
  4 import psycopg2
  5 import time
  6 from io import StringIO
  7 from common import log_helper, file_helper
  8 
  9 
 10 class PgHelper(object):
 11     """postgresql数据库操作类"""
 12 
 13     def __init__(self, db, is_output_sql):
 14         self.connect = None
 15         self.cursor = None
 16         # 初始化数据库参数
 17         self.db_name = db.get('db_name', '')
 18         self.db_user = db.get('db_user', '')
 19         self.db_pass = db.get('db_pass', '')
 20         self.db_host = db.get('db_host', '')
 21         self.db_port = db.get('db_port', '')
 22         # 是否将所有要执行的Sql语句输出到日志里
 23         self.is_output_sql = is_output_sql
 24 
 25     def open_conn(self):
 26         """连接数据库,并建立游标"""
 27         try:
 28             if not self.connect:
 29                 self.connect = psycopg2.connect(database=self.db_name, user=self.db_user, password=self.db_pass,
 30                                                 host=self.db_host, port=self.db_port)
 31             return self.connect
 32         except Exception as e:
 33             log_helper.error('连接数据库失败:' + str(e.args))
 34             return False
 35 
 36     def close_conn(self):
 37         """关闭postgresql数据库链接"""
 38         # 关闭游标
 39         try:
 40             if self.cursor:
 41                 self.cursor.close()
 42         except Exception:
 43             pass
 44         # 关闭数据库链接
 45         try:
 46             if self.connect:
 47                 self.connect.close()
 48         except Exception:
 49             pass
 50 
 51     def __enter__(self):
 52         """初始化数据库链接"""
 53         self.open_conn()
 54         return self
 55 
 56     def __exit__(self, type, value, trace):
 57         """关闭postgresql数据库链接"""
 58         self.close_conn()
 59 
 60     def rollback(self):
 61         """回滚操作"""
 62         try:
 63             # 异常时,进行回滚操作
 64             if self.connect:
 65                 self.connect.rollback()
 66         except Exception as e:
 67             log_helper.error('回滚操作失败:' + str(e.args))
 68 
 69     def commit(self):
 70         """提交事务"""
 71         try:
 72             if self.connect:
 73                 self.connect.commit()
 74                 self.close_conn()
 75         except Exception as e:
 76             log_helper.error('提交事务失败:' + str(e.args))
 77 
 78     def get_sql(self, query, vars=None):
 79         """获取编译后的sql语句"""
 80         # 记录程序执行开始时间
 81         start_time = time.clock()
 82         try:
 83             # 判断是否记录sql执行语句
 84             if self.is_output_sql:
 85                 log_helper.info('sql:' + str(query))
 86             # 建立游标
 87             self.cursor = self.connect.cursor()
 88             # 执行SQL
 89             self.data = self.cursor.mogrify(query, vars)
 90         except Exception as e:
 91             # 将异常写入到日志中
 92             log_helper.error('sql生成失败:' + str(e.args) + ' query:' + str(query))
 93             self.data = '获取编译sql失败'
 94         finally:
 95             # 关闭游标
 96             self.cursor.close()
 97         # 记录程序执行结束时间
 98         end_time = time.clock()
 99         # 写入日志
100         self.write_log(start_time, end_time, query)
101 
102         return self.data
103 
104     def copy(self, values, table_name, columns):
105         """
106         百万级数据更新函数
107         :param values: 更新内容,字段之间用\t分隔,记录之间用\n分隔 "1\taaa\tabc\n2\bbb\abc\n"
108         :param table_name: 要更新的表名称
109         :param columns: 需要更新的字段名称:例:('id','userame','passwd')
110         :return:
111         """
112         try:
113             # 建立游标
114             self.cursor = self.connect.cursor()
115             self.cursor.copy_from(StringIO(values), table_name, columns=columns)
116             self.connect.commit()
117             return True
118         except Exception as e:
119             # 将异常写入到日志中
120             log_helper.error('批量更新失败:' + str(e.args) + ' table:' + table_name)
121         finally:
122             # 关闭游标
123             self.cursor.close()
124 
125     def execute(self, query, vars=None):
126         """执行sql语句查询,返回结果集或影响行数"""
127         if not query:
128             return None
129         # 记录程序执行开始时间
130         start_time = time.clock()
131         try:
132             # 判断是否记录sql执行语句
133             if self.is_output_sql:
134                 log_helper.info('sql:' + str(query))
135             # 建立游标
136             self.cursor = self.connect.cursor()
137             # 执行SQL
138             result = self.cursor.execute(query, vars)
139             print(str(result))
140         except Exception as e:
141             # 将异常写入到日志中
142             log_helper.error('sql执行失败:' + str(e.args) + ' query:' + str(query))
143             self.data = None
144         else:
145             # 获取数据
146             try:
147                 if self.cursor.description:
148                     # 在执行insert/update/delete等更新操作时,如果添加了returning,则读取返回数据组合成字典返回
149                     self.data = [dict((self.cursor.description[i][0], value) for i, value in enumerate(row)) for row in self.cursor.fetchall()]
150                 else:
151                     # 如果执行insert/update/delete等更新操作时没有添加returning,则返回影响行数,值为0时表时没有数据被更新
152                     self.data = self.cursor.rowcount
153             except Exception as e:
154                 # 将异常写入到日志中
155                 log_helper.error('数据获取失败:' + str(e.args) + ' query:' + str(query))
156                 self.data = None
157         finally:
158             # 关闭游标
159             self.cursor.close()
160         # 记录程序执行结束时间
161         end_time = time.clock()
162         # 写入日志
163         self.write_log(start_time, end_time, query)
164 
165         # 如果有返回数据,则把该数据返回给调用者
166         return self.data
167 
168 
169     def write_log(self, start_time, end_time, sql):
170         """记录Sql执行超时日志"""
171         t = end_time - start_time
172         if (t) > 0.1:
173             content = ' '.join(('run time:', str(t), 's sql:', sql))
174             log_helper.info(content)

  BaseController

Shelf_Init.sql

继续,插入BookNbr信息;

主要:

  在配置中,我们同样定义了数据库连接地址、端口、数据库名称、用户名与密码。

  部分视图Students.cshtml

Init.cshtml

 1 CREATE PROCEDURE [base].[BookAuthor#Insert](@json nvarchar(max), @bookID bigint)
 2 WITH ENCRYPTION
 3 AS
 4 BEGIN
 5 ...
 6 
 7         -- insert Author
 8         insert    base._Author(Name)select value
 9         from    openjson(@json, '$.Authors') x
10         where    not exists(select 1 from base._Author p where p.Name=x.value);
11 
12         insert    base._BookAuthor(BookID, AuthorID) select @bookID, x.ID
13         from    openjson(@json, '$.Authors') j join base.Author#Raw() x on x.Name=j.value
14 
15 ...
16 END

自动加载类

  通过重写内置__enter__()与__exit__()方法,来实现with语句调用本类时,会自动对类进行初始化操作,自动创建数据库连接。当代码执行完毕后(程序退出with语句时),程序会自动调用对应的方法,将游标与数据库连接的关闭,避免手动操作时,忘记关闭连接出现异常。

□ 思路

….

 


View Code

using System;

using System.Collections.Generic;

using DataAnnotationAjax.Models;

 

namespace DataAnnotationAjax.Service

{

    public static class StudentRepository

    {

        private static int _idSeed = 1;

        private static readonly List<Student>  _students = new List<Student>();

 

        static StudentRepository()

        {

            Random rand = new Random();

            for (int i = 0; i < 3; i++)

            {

                var student = new Student();

                int id = _idSeed++;

                student.Id = id;

                student.Name = "姓名" + id.ToString();

                student.Score = (60 + Convert.ToInt16(rand.NextDouble()*40));

                student.Enrollment = DateTime.Now;

                _students.Add(student);

            }

        }

 

        public static void AddStudent(Student stu)

        {

            stu.Id = _idSeed++;

            stu.Enrollment = DateTime.Now;

            _students.Add(stu);

        }

 

        public static List<Student> GetStudents()

        {

            return _students;

        }

    }

}

 

哈哈,看来一切正常。

 

  思路

  问题:
此时,入口文件代码零碎增多,随着后续代码的增加,入口文件会更加臃肿复杂,不易管理

  解决方法:
封装入口文件中的操作称为一个类,这样只需要在入口文件调用类的方法即可

    创建Init.class.php类文件,放入到Frame中
   将入口文件所有操作封装成类方法
loadClass() 设置自动加载函数
autoload()自动加载类
setConst() 定义常量
dispatch() 前端分发器

  在config目录下创建db_config.py文件(有多个库时,可以配置多个不同的参数来引用)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace DataAnnotationAjax.Controllers
{
    public class BaseController : Controller
    {
        /// <summary>
        /// 把部分视图转换成string
        /// </summary>
        /// <param name="viewName">部分视图名称</param>
        /// <param name="model">view model</param>
        /// <returns>部分视图字符串</returns>
        public string RenderPartialViewToString(string viewName, object model)
        {
            ViewData.Model = model;
            using (var sw = new StringWriter())
            {
                //根据部分视图名称+ControllerContext获得ViewEngineResult
                //ViewEngineResult中有View属性
                var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);

                //创建ViewContext对象实例
                var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);

                //把ViewEngineResult中的视图渲染到StringWriter实例中
                viewResult.View.Render(viewContext,sw);

                //获取视图string
                return sw.GetStringBuilder().ToString();
            }
        }

        /// <summary>
        /// 获取ModelState中的错误信息,以字典集合的形式返回
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, object> GetErrorFromModelState()
        {
            var errors = new Dictionary<string, object>();
            foreach (var key in ModelState.Keys)
            {
                if (ModelState[key].Errors.Count > 0)
                {
                    errors[key] = ModelState[key].Errors;
                }
            }
            return errors;
        }
    }
}

留下评论

网站地图xml地图