[关闭]
@Aiti 2019-09-23T08:41:11.000000Z 字数 6731 阅读 311

基于MVC和WebApi的.Net项目

MVC WebApi .Net XPO Swagger


1. 选择Visual C# 的ASP.NET Web应用程序(.Net Framework)

1.png

2. 管理NuGet库,添加swagger框架,可以自动生成接口文档和客户端服务端代码,方便测试

2.png

3. 管理NuGet库,添加XPO框架,可以自动持久化实体类,映射数据库

4.png

4. 设置web.config链接数据库和用于持久化实体类的session

1.web.config里面配置:

  1. <appSettings>
  2. <add key="XpoConnectionString" value="XpoProvider=MSSqlServer;data source=.;user id=sa;password=cx1234;initial catalog=TestWeb;Persist Security Info=true" />
  3. </appSettings>

2.封装XpoHelper方法用于获取session

6.png

3.控制器基类-ApiControllerBase类中获取session

  1. public DevExpress.Xpo.Session session => XpoHelper.Session;

5.创建实体类

5.png

6. 添加共用的控制器基类

继承System.Web.Http.ApiController 的 ApiControllerBase类,被所有控制器继承,用于控制器接口类的通用处理,如文件的处理、session的设置.

3.png

7.编写控制器进行数据存储与获取

  1. 如下图,POST方法可以进行数据存储到数据库,并自动建立没有的库和表,到此后台已经和数据库打通了。

7.png

2、Get方法因为返回的数据前端不能序列化,[导致报错]:ObjectContent`1”类型未能序列化内容类型“application/json; charset=utf-8”的响应正文。所以用到下面的视图类,设置返回的数据。

8.创建视图类,将实体类映射到视图类

9.png

9.添加AutoMapper框架,将实体类映射到视图类

8.png

安装成功后,编写一个类(需继承AutoMapper中的基类 Profile)来存放实体类和视图类的映射关系

  1. namespace TestWeb.App_Start
  2. {
  3. public class AutoMapperProfile: Profile
  4. {
  5. public AutoMapperProfile()
  6. {
  7. CreateMap<User, vUser>();
  8. }
  9. }
  10. }
  1. public vUser Get(string loginname)
  2. {
  3. var user = session.FindObject<User>(loginname);
  4. return AutoMapper.Mapper.Map<vUser>(user);
  5. }

在这里运行的话会提示AutoMapper没有初始化,Mapper not initialized.所以需要初始化AutoMapper;
需要在使用之前初始化,所以可以在Startup或者Global里面初始化;

  1. Mapper.Initialize(x =>
  2. {
  3. x.CreateMap<User, vUser>();
  4. });
  1. Mapper.Initialize(x => x.AddProfile<AutoMapperProfile>());

10添加修改数据,将接收到的视图数据转换成XPO存入数据库

新增数据和编辑修改数据用同一个接口,所以首先要找到该类型的主键,判断其是否为null,如果为null,即新增数据;不为null,即编辑数据;新增时,主键不传或者传null,

  1. /// <summary>
  2. /// 视图类转换XPO实体类
  3. /// </summary>
  4. public class ViewModelToXpoHelper
  5. {
  6. public static object GetKeyValue(BaseViewModel vModel, Type t, Session session)
  7. {
  8. var keyFiled = session.GetClassInfo(t).KeyProperty.Name;
  9. var mc = new PropertyAccessor(vModel.GetType(), keyFiled);
  10. return mc.Get(vModel);
  11. }
  12. /// <summary>
  13. /// 视图类转换XPO实体类
  14. /// </summary>
  15. /// <typeparam name="T"></typeparam>
  16. /// <param name="vModel"></param>
  17. /// <param name="session"></param>
  18. /// <returns></returns>
  19. public static T ViewModelToXpo<T>(BaseViewModel vModel,Session session, XPBaseObject xpOrgin = null) where T: XPBaseObject
  20. {
  21. try
  22. {
  23. T xpoModel;
  24. if (xpOrgin == null)
  25. {
  26. var keyValue = GetKeyValue(vModel, typeof(T), session);
  27. if (keyValue == null)
  28. {
  29. //新建记录
  30. XPClassInfo classInfo = session.GetClassInfo(typeof(T));
  31. xpoModel = (T)classInfo.CreateNewObject(session);
  32. }
  33. else
  34. {
  35. //编辑记录
  36. xpoModel = session.GetObjectByKey<T>(keyValue);
  37. }
  38. }
  39. else
  40. xpoModel = xpOrgin as T;
  41. //反射 填充xpo
  42. foreach (PropertyInfo pInfo in vModel.GetType().GetProperties())
  43. {
  44. try
  45. {
  46. var v = pInfo.GetValue(vModel);
  47. if (v != null)
  48. {
  49. if (pInfo.PropertyType.IsSubclassOf(typeof(BaseViewModel)))
  50. {
  51. Type t = xpoModel.ClassInfo.GetMember(pInfo.Name).MemberType;
  52. xpoModel.SetMemberValue(pInfo.Name, session.GetObjectByKey(t, GetKeyValue((BaseViewModel)v, t, session)));
  53. }
  54. else
  55. {
  56. xpoModel.SetMemberValue(pInfo.Name, v);
  57. }
  58. }
  59. }
  60. catch { }
  61. }
  62. return xpoModel;
  63. }
  64. catch(Exception e)
  65. {
  66. }
  67. return null;
  68. }
  69. }
  1. public vUser Post([FromBody]vUser v)
  2. {
  3. var o = ViewModelToXpoHelper.ViewModelToXpo<User>(v, session,v.IsNew? new User(session):null);
  4. return AutoMapper.Mapper.Map<vUser>(o);
  5. }

11.删除数据

  1. public IHttpActionResult Delete(string loginname)
  2. {
  3. var user = session.GetObjectByKey<User>(loginname);
  4. user.Delete();
  5. return Ok("删除成功!");
  6. }

12.设置路由,API路径,设置请求方式

11.png

13.增加搜索条件获取列表,带分页的

请求带分页的列表:
1. 首先接收的对象需要包括:请求页码、请求页码大小(每页显示数量),请求条件集合;
2. 根据接收的对象中的请求条件对数据进行过滤等到实体类的List集合;
3. 需要AutoMapper将实体类的List集合进行映射到视图发送给前端,前端接收到的对象包括:list集合,当前页码、页码大小、总页数、总元素个数
4. 所以也要有对应的一个类对象包含前端接收的这些数据才能通过AutoMapper映射给前端(可以理解为User和vUser通过Mapper映射的,vUser里有的属性,User里面肯定有;反之不一定)
5. 这里可能涉及LINQ 和 Lambda 表达式 以及 DevExpress的CriteriaOperator过滤对象;需要提前学习。
看代码:
1、接收请求的类
12.png
2、数据处理后传给前端的视图类
13.png
3、需要通过Mapper映射给前端的类,这里包括了前端视图类所需要的属性,还有写了构造函数和方法,new一个对象时,通过构造函数和方给这些前端视图类需要的对应的属性赋值。

  1. namespace TestWeb.Common.Engine
  2. {
  3. /// <summary>
  4. /// 分页
  5. /// </summary>
  6. /// <typeparam name="T"></typeparam>
  7. public class PageingHelper<T>
  8. {
  9. /// <summary>
  10. /// 分页编号
  11. /// </summary>
  12. public int CurrentPage { get; set; }
  13. /// <summary>
  14. /// 分页大小
  15. /// </summary>
  16. public int PageSize { get; private set; }
  17. private int? _totalCount;
  18. /// <summary>
  19. /// 元素总共数目
  20. /// </summary>
  21. public int TotalCount
  22. {
  23. get
  24. {
  25. if (_totalCount == null) _totalCount = Query.Count();
  26. return (int)_totalCount;
  27. }
  28. }
  29. /// <summary>
  30. /// 页数
  31. /// </summary>
  32. public int PageCount
  33. {
  34. get
  35. {
  36. return TotalCount == 0 ? 0 : (int)Math.Ceiling((decimal)TotalCount / PageSize);
  37. }
  38. }
  39. private IQueryable<T> Query { get; set; }
  40. public List<T> List { get; private set; }
  41. /// <summary>
  42. /// 构造函数
  43. /// </summary>
  44. /// <param name="list">链表</param>
  45. /// <param name="intPageIndex">编号</param>
  46. /// <param name="intPageSize">大小</param>
  47. public PageingHelper(IQueryable<T> list, int intPageIndex, int intPageSize)
  48. {
  49. CurrentPage = intPageIndex;
  50. PageSize = intPageSize;
  51. Query = list;
  52. GetPagedList();
  53. }
  54. /// <summary>
  55. /// 转为为分页
  56. /// </summary>
  57. /// <param name="list">链表</param>
  58. public void GetPagedList()
  59. {
  60. if (CurrentPage > PageCount) CurrentPage = PageCount;
  61. if (CurrentPage < 1) CurrentPage = 1;
  62. int intStart = (CurrentPage - 1) * PageSize;
  63. List = Query.Skip(intStart).Take(PageSize).ToList();
  64. }
  65. }
  66. }

4、将已经过滤的List集合通过Mapper映射返回给前端
15.png

14.给接口添加注释并显示

首先选择项目注释信息的生成位置

16.png
20.png

1、给Web的Help Api添加注释

17.png
18.png

2、给swagger添加注释信息

19.png

15.密码加密

1.密码加密
选择MD5加密方式加密,

  1. [Persistent("Password"),Size(20)]
  2. private string _password;
  3. [DisplayName("密码")]
  4. public string Password
  5. {
  6. get { return _password; }
  7. set { _password = ConvertHelper.MD5(value); }
  8. }

加密帮助类

  1. using System;
  2. using System.Security.Cryptography;
  3. using System.Text;
  4. public class ConvertHelper
  5. {
  6. /// <summary>
  7. /// MD加密
  8. /// </summary>
  9. /// <param name="value">源值</param>
  10. /// <param name="salt">盐值</param>
  11. /// <returns></returns>
  12. public static string MD5(string value,string salt="Aiti")
  13. {
  14. byte[] v = Encoding.Default.GetBytes(salt + value.ToString());
  15. MD5 md = new MD5CryptoServiceProvider();
  16. byte[] mv = md.ComputeHash(v);
  17. return BitConverter.ToString(mv).Replace("-", "");
  18. }
  19. }

16.登录

1、继承 System.Web.HttpApplication 的 FormsAuthenticationHttpApplication类,被Global继承,用于登录时信息验证

  1. public class FormsAuthenticationHttpApplication : System.Web.HttpApplication
  2. {
  3. //身份验证
  4. protected void Application_AuthenticateRequest(object sender, EventArgs e)
  5. {
  6. try
  7. {
  8. if (HttpContext.Current.User != null)
  9. {
  10. if (HttpContext.Current.User.Identity.IsAuthenticated)
  11. {
  12. if (HttpContext.Current.User.Identity is FormsIdentity)
  13. {
  14. FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
  15. FormsAuthenticationTicket ticket = id.Ticket;
  16. string userData = ticket.UserData;
  17. string[] roles = userData.Split(',');
  18. HttpContext.Current.User = new GenericPrincipal(id, roles);
  19. }
  20. }
  21. }
  22. }
  23. catch
  24. {
  25. Response.Write(Context.User.Identity.AuthenticationType);
  26. Response.End();
  27. }
  28. }
  29. }

在上面写了身份验证还需要去web.config中设置验证方式为Forms表单验证

  1. <system.web>
  2. <authentication mode="Forms">
  3. <forms loginUrl="/home/login" enableCrossAppRedirects="true" protection="All" slidingExpiration="true" timeout="60" />
  4. </authentication>
  5. </system.web>

这样登录页登录过后,再次进入页面就不需要再进行登录,会记录登录状态。
前后端分离时,前端也要控制cookie,切换浏览器要跳出重新登录。
或者web.config中添加sessionState的mode模式

  1. <system.web>
  2. <sessionState mode="InProc" timeout="20" />
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注