基础代码
parent
5b03dfb8b4
commit
b89a23e1fd
|
|
@ -0,0 +1,226 @@
|
|||
<%--
|
||||
Author: yubaolee
|
||||
Description: 用于生成OpenAuth.WebApi接口相关代码,包括controller/app/实体/dbcontext
|
||||
--%>
|
||||
<%@ Template Language="C#" TargetLanguage="Text" Debug="True" OutputType="Normal" %>
|
||||
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Assembly Name="CodeSmith.CustomProperties" %>
|
||||
|
||||
<%@ Assembly Name="Mono.Cecil" Path="..\Common" %>
|
||||
<%@ Assembly Name="ICSharpCode.NRefactory" Path="..\Common" %>
|
||||
<%@ Assembly Name="ICSharpCode.NRefactory.CSharp" Path="..\Common" %>
|
||||
|
||||
<%@ Assembly Src="Internal\Model.cs" %>
|
||||
<%@ Assembly Src="Internal\Extensions.cs" %>
|
||||
<%@ Assembly Src="Internal\Generator.cs" %>
|
||||
<%@ Assembly Src="Internal\Parser.cs" %>
|
||||
|
||||
<%@ Import Namespace="System.Collections.Generic" %>
|
||||
<%@ Import Namespace="System.IO" %>
|
||||
<%@ Import Namespace="System.Linq" %>
|
||||
<%@ Import Namespace="System.Text" %>
|
||||
<%@ Import Namespace="System.Text.RegularExpressions" %>
|
||||
<%@ Import Namespace="System.Diagnostics" %>
|
||||
|
||||
<%@ Import Namespace="SchemaMapper" %>
|
||||
|
||||
<%@ Property Name="WholeDb"
|
||||
Type="System.Boolean"
|
||||
Category="1.Database"
|
||||
Default="true"
|
||||
Description="是否直接生成选定数据库中的所有表" %>
|
||||
|
||||
<%@ Property Name="HeaderModel"
|
||||
Type="System.Boolean"
|
||||
Category="1.Database"
|
||||
Default="true"
|
||||
Description="是否为启用头表模式,即类似‘入库订单’界面" %>
|
||||
|
||||
<%@ Property Name="SourceDatabase"
|
||||
Type="SchemaExplorer.DatabaseSchema"
|
||||
Category="1.Database"
|
||||
Description="The source database." %>
|
||||
|
||||
<%@ Property Name="SourceTables"
|
||||
Type="SchemaExplorer.TableSchemaCollection"
|
||||
Category="1.Database" Description="可以选择一个或多个表(使用Ctrl键)" %>
|
||||
|
||||
<%@ Property Name="directory"
|
||||
Type="System.String"
|
||||
Default=".\"
|
||||
Optional="True"
|
||||
Description="代码生成路径"
|
||||
Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>
|
||||
|
||||
<%@ Property Name="ContextNamespace"
|
||||
Type="System.String"
|
||||
Category="2.Class"
|
||||
Default="OpenAuth.Repository"
|
||||
OnChanged="OnContextNamespaceChanged"
|
||||
Description="DbContext默认命名空间,尽量不要更改"%>
|
||||
<%@ Property Name="EntityNamespace"
|
||||
Type="System.String"
|
||||
Default="OpenAuth.Repository.Domain"
|
||||
Category="2.Class"
|
||||
Description="实体默认命名空间,尽量不要更改"%>
|
||||
|
||||
|
||||
<%@ Register Name="EntityGeneratedClass"
|
||||
Template="Internal\Entity.Generated.cst"
|
||||
MergeProperties="False" %>
|
||||
|
||||
<%@ Register Name="ContextGeneratedClass"
|
||||
Template="Internal\Context.Generated.cst"
|
||||
MergeProperties="True" %>
|
||||
|
||||
<%@ Register Name="ApplicationGenerateClass"
|
||||
Template="ApiGenerate\Application.cst"
|
||||
MergeProperties="False" %>
|
||||
<%@ Register Name="RequestGenerateClass"
|
||||
Template="ApiGenerate\Request.cst"
|
||||
MergeProperties="False" %>
|
||||
<%@ Register Name="ModifyReqGenerateClass"
|
||||
Template="ApiGenerate\ModifyReq.cst"
|
||||
MergeProperties="False" %>
|
||||
<%@ Register Name="ControllerGenerateClass"
|
||||
Template="ApiGenerate\Controller.cst"
|
||||
MergeProperties="False" %>
|
||||
|
||||
开始创建OpenAuth.Core WebApi相关代码 ...
|
||||
<% Generate(); %>
|
||||
|
||||
<script runat="template">
|
||||
private TableSchemaCollection tables;
|
||||
public void Generate()
|
||||
{
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
string outputDirectory = Path.GetFullPath(directory);
|
||||
|
||||
if(WholeDb){
|
||||
tables = SourceDatabase.Tables;
|
||||
}
|
||||
else{
|
||||
tables = SourceTables;
|
||||
}
|
||||
|
||||
CreateEntityClasses();
|
||||
CreateControllerClass();
|
||||
CreateApplicationClass();
|
||||
CreateReqClass();
|
||||
CreateContextClass();
|
||||
|
||||
watch.Stop();
|
||||
Response.WriteLine("Generate Time: " + watch.ElapsedMilliseconds + " ms");
|
||||
}
|
||||
|
||||
//创建实体类
|
||||
public void CreateEntityClasses()
|
||||
{
|
||||
EntityGeneratedClass generatedClass = this.Create<EntityGeneratedClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
string className = table.Name;
|
||||
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.Repository\\Domain\\" + className + ".cs";
|
||||
|
||||
generatedClass.Table = table;
|
||||
Response.WriteLine("已生成"+generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//创建DbContext
|
||||
public void CreateContextClass()
|
||||
{
|
||||
ContextGeneratedClass generatedClass = this.Create<ContextGeneratedClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
string dbContextName;
|
||||
if(WholeDb){
|
||||
dbContextName = SourceDatabase.Name.ToSafeName();
|
||||
}
|
||||
else{
|
||||
dbContextName = SourceTables.First().Database.Name.ToSafeName();
|
||||
}
|
||||
dbContextName = StringUtil.ToPascalCase(dbContextName);
|
||||
|
||||
string generatedFile = "OpenAuth.Repository\\" + dbContextName + "Context.cs";
|
||||
|
||||
Response.WriteLine("重要提示!!!!把下面内容添加到"+generatedFile+"对应的位置中,千万不要直接覆盖!!!");
|
||||
Response.WriteLine(generatedClass.RenderToString());
|
||||
}
|
||||
|
||||
|
||||
//创建控制器,如UserManagerController.cs
|
||||
public void CreateControllerClass()
|
||||
{
|
||||
ControllerGenerateClass generatedClass = this.Create<ControllerGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.WebApi\\Controllers\\"+ table.Name + "sController.cs";
|
||||
|
||||
generatedClass.ModuleName = table.Name;
|
||||
|
||||
Response.WriteLine("已生成"+generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
//创建APP层,如UserManagerApp.cs
|
||||
public void CreateApplicationClass()
|
||||
{
|
||||
ApplicationGenerateClass generatedClass = this.Create<ApplicationGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.App\\"+ table.Name +"\\"+ table.Name + "App.cs";
|
||||
generatedClass.Table = table;
|
||||
//generatedClass.Entity = entity;
|
||||
Response.WriteLine("已生成"+generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//创建请求参数,如QueryUserListReq.cs
|
||||
public void CreateReqClass()
|
||||
{
|
||||
RequestGenerateClass generatedClass = this.Create<RequestGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.App\\"+ table.Name +"\\Request\\Query"+ table.Name + "ListReq.cs";
|
||||
generatedClass.ModuleName = table.Name;
|
||||
Response.WriteLine("已生成"+generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
|
||||
//生成编辑修改的请求参数
|
||||
ModifyReqGenerateClass modifyReqGenerateClass = this.Create<ModifyReqGenerateClass>();
|
||||
this.CopyPropertiesTo(modifyReqGenerateClass);
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.App\\"+ table.Name +"\\Request\\AddOrUpdate"+ table.Name + "Req.cs";
|
||||
modifyReqGenerateClass.Table = table;
|
||||
Response.WriteLine("已生成"+generatedFile);
|
||||
modifyReqGenerateClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnContextNamespaceChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ContextNamespace))
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(EntityNamespace))
|
||||
EntityNamespace = ContextNamespace + ".Domain";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
<%--
|
||||
Name: Database Table Properties
|
||||
Author: yubaolee
|
||||
Description: Create a list of properties from a database table
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="True" Description="应用层" %>
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
<%@ Property Name="Table"
|
||||
Type="SchemaExplorer.TableSchema" %>
|
||||
<%@ Property Name="HeaderModel"
|
||||
Type="System.Boolean"
|
||||
Category="1.Database"
|
||||
Default="true"
|
||||
Description="是否为启用头表模式,即类似‘入库订单’界面" %>
|
||||
<%@ Assembly Src="../Web/Util.cs" %>
|
||||
<%@ Import Namespace="Util" %>
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using OpenAuth.Repository.Interface;
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class <%=Table.Name%>App : BaseStringApp<<%=Table.Name%>, OpenAuthDBContext>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
/// <summary>
|
||||
/// 加载列表
|
||||
/// </summary>
|
||||
public TableData Load(Query<%=Table.Name%>ListReq request)
|
||||
{
|
||||
var loginContext = _auth.GetCurrentUser();
|
||||
if (loginContext == null)
|
||||
{
|
||||
throw new CommonException("登录已过期", Define.INVALID_TOKEN);
|
||||
}
|
||||
//如果是WebAPI,请务必改为loginContext.GetTableColumns("<%=Table.Name%>");
|
||||
var columnFields = loginContext.GetTableColumnsFromDb("<%=Table.Name%>");
|
||||
if (columnFields == null || columnFields.Count == 0)
|
||||
{
|
||||
throw new Exception("请在代码生成界面配置Category表的字段属性");
|
||||
}
|
||||
var result = new TableData();
|
||||
var objs = UnitWork.Find<<%=Table.Name%>>(null);
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
objs = objs.Where(u => u.Id.Contains(request.key));
|
||||
}
|
||||
var propertyStr = string.Join(',', columnFields.Select(u =>u.ColumnName));
|
||||
result.columnFields = columnFields;
|
||||
result.data = objs.OrderBy(u => u.Id)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).Select($"new ({propertyStr})");
|
||||
result.count = objs.Count();
|
||||
return result;
|
||||
}
|
||||
<%
|
||||
if(Table.Name.Contains("Tbl") && (!Table.Name.Contains("Dtbl")) && this.HeaderModel){
|
||||
var dtblName = Table.Name.Replace("Tbl","Dtbl"); //明细表的表名
|
||||
%>
|
||||
public void Add(AddOrUpdate<%=Table.Name%>Req req)
|
||||
{
|
||||
var obj = req.MapTo<<%=Table.Name%>>();
|
||||
//todo:根据自己的业务场景,补充或调整字段
|
||||
obj.CreateTime = DateTime.Now;
|
||||
var user = _auth.GetCurrentUser().User;
|
||||
obj.CreateUserId = user.Id;
|
||||
obj.CreateUserName = user.Name;
|
||||
UnitWork.Add(obj);
|
||||
if (req.<%=dtblName%>Reqs != null && req.<%=dtblName%>Reqs.Any())
|
||||
{
|
||||
foreach (var detail in req.<%=dtblName%>Reqs)
|
||||
{
|
||||
detail.ForeignKeyId = obj.Id; //todo:调整自己的明细表外键
|
||||
_<%=dtblName%>App.AddNoSave(detail);
|
||||
}
|
||||
}
|
||||
UnitWork.Save();
|
||||
}
|
||||
public void Update(AddOrUpdate<%=Table.Name%>Req obj)
|
||||
{
|
||||
var user = _auth.GetCurrentUser().User;
|
||||
if (obj.<%=dtblName%>Reqs != null && obj.<%=dtblName%>Reqs.Any())
|
||||
{
|
||||
//id为空的添加
|
||||
foreach (var detail in obj.<%=dtblName%>Reqs.Where(u =>string.IsNullOrEmpty(u.Id)))
|
||||
{
|
||||
detail.ForeignKeyId = obj.Id; //todo:调整自己的明细表外键
|
||||
_<%=dtblName%>App.AddNoSave(detail);
|
||||
}
|
||||
//id比数据库少的,删除
|
||||
var containids = obj.<%=dtblName%>Reqs.Select(u => u.Id)
|
||||
.Where(u =>!string.IsNullOrEmpty(u)).ToList();
|
||||
if (containids.Any())
|
||||
{
|
||||
UnitWork.Delete<<%=dtblName%>>(u =>(!containids.Contains(u.Id)) && u.ForeignKeyId == obj.Id); //todo:调整自己的明细表外键
|
||||
}
|
||||
//更新id相同的
|
||||
foreach (var detail in obj.<%=dtblName%>Reqs.Where(u =>!string.IsNullOrEmpty(u.Id)))
|
||||
{
|
||||
_<%=dtblName%>App.Update(detail);
|
||||
}
|
||||
}
|
||||
<%CreateUpdate();%>
|
||||
UnitWork.Save();
|
||||
}
|
||||
<%
|
||||
}else{ %>
|
||||
public void Add(AddOrUpdate<%=Table.Name%>Req req)
|
||||
{
|
||||
var obj = req.MapTo<<%=Table.Name%>>();
|
||||
//todo:根据自己的业务场景,补充或调整字段
|
||||
//比如:obj.CreateTime = DateTime.Now;
|
||||
// var user = _auth.GetCurrentUser().User;
|
||||
// obj.CreateUserId = user.Id;
|
||||
// obj.CreateUserName = user.Name;
|
||||
Repository.Add(obj);
|
||||
}
|
||||
public void Update(AddOrUpdate<%=Table.Name%>Req obj)
|
||||
{
|
||||
<%CreateUpdate();%>
|
||||
}
|
||||
<%
|
||||
}
|
||||
%>
|
||||
public <%=Table.Name%>App(IUnitWork<OpenAuthDBContext> unitWork, IRepository<<%=Table.Name%>, OpenAuthDBContext> repository,
|
||||
RevelanceManagerApp app, IAuth auth) : base(unitWork, repository,auth)
|
||||
{
|
||||
_revelanceApp = app;
|
||||
}
|
||||
}
|
||||
}
|
||||
<script runat="template">
|
||||
/// <summary>
|
||||
/// 创建更新字段
|
||||
/// </summary>
|
||||
public void CreateUpdate() {
|
||||
var updatestr = Tools.CreateBlank(1) + "UnitWork.Update<" + Table.Name + ">(u => u.Id == obj.Id, u => new " + Table.Name + "\r\n";
|
||||
updatestr +=Tools.CreateBlank(1) + "{\r\n";
|
||||
var columnstr = "";
|
||||
foreach (ColumnSchema p in Table.Columns) {
|
||||
if (p.IsPrimaryKeyMember) continue ;
|
||||
columnstr += Tools.CreateBlank(2)+ p.Name + " = obj." + p.Name + ", \r\n";
|
||||
}
|
||||
columnstr = columnstr.Substring(0, columnstr.Length - 4); //删除最后一个逗号
|
||||
updatestr += columnstr;
|
||||
updatestr += "\r\n" +Tools.CreateBlank(2) +"//todo:根据自己的业务场景,补充或调整字段";
|
||||
updatestr += "\r\n" +Tools.CreateBlank(1) +"});";
|
||||
Response.WriteLine(updatestr);
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<%--
|
||||
Name: Database Table Properties
|
||||
Author: yubaolee
|
||||
Description: Create a list of properties from a database table
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="True" Description="控制器" %>
|
||||
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
|
||||
using System;
|
||||
using Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenAuth.App;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
|
||||
namespace OpenAuth.WebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// <%=ModuleName%>操作
|
||||
/// </summary>
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class <%=ModuleName%>sController : ControllerBase
|
||||
{
|
||||
private readonly <%=ModuleName%>App _app;
|
||||
|
||||
/// <summary>
|
||||
/// //获取详情
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public Response<<%=ModuleName%>> Get(string id)
|
||||
{
|
||||
var result = new Response<<%=ModuleName%>>();
|
||||
try
|
||||
{
|
||||
result.Result = _app.Get(id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Response Add(AddOrUpdate<%=ModuleName%>Req obj)
|
||||
{
|
||||
var result = new Response();
|
||||
try
|
||||
{
|
||||
_app.Add(obj);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Response Update(AddOrUpdate<%=ModuleName%>Req obj)
|
||||
{
|
||||
var result = new Response();
|
||||
try
|
||||
{
|
||||
_app.Update(obj);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载列表
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public TableData Load([FromQuery]Query<%=ModuleName%>ListReq request)
|
||||
{
|
||||
return _app.Load(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Response Delete([FromBody]string[] ids)
|
||||
{
|
||||
var result = new Response();
|
||||
try
|
||||
{
|
||||
_app.Delete(ids);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public <%=ModuleName%>sController(<%=ModuleName%>App app)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %>
|
||||
|
||||
<%@ Assembly Src="../Internal/Model.cs" %>
|
||||
<%@ Assembly Src="../Internal/Extensions.cs" %>
|
||||
|
||||
<%@ Import Namespace="System.Collections.Generic" %>
|
||||
<%@ Import Namespace="System.Linq" %>
|
||||
<%@ Import Namespace="System.Text" %>
|
||||
<%@ Import Namespace="System.Text.RegularExpressions" %>
|
||||
|
||||
<%@ Import Namespace="SchemaMapper" %>
|
||||
|
||||
<%@ Property Name="Table"
|
||||
Type="SchemaExplorer.TableSchema" %>
|
||||
|
||||
<%@ Property Name="HeaderModel"
|
||||
Type="System.Boolean"
|
||||
Category="1.Database"
|
||||
Default="true"
|
||||
Description="是否为启用头表模式,即类似‘入库订单’界面" %>
|
||||
|
||||
<%@ Property Name="EntityNamespace"
|
||||
Type="System.String" %>
|
||||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a CodeSmith Template.
|
||||
//
|
||||
// DO NOT MODIFY contents of this file. Changes to this
|
||||
// file will be lost if the code is regenerated.
|
||||
// Author:Yubao Li
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
using OpenAuth.Repository.Core;
|
||||
|
||||
namespace OpenAuth.App.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// <%= Table.Description %>
|
||||
/// </summary>
|
||||
[Table("<%= Table.Name%>")]
|
||||
public partial class AddOrUpdate<%= Table.Name %>Req
|
||||
{
|
||||
|
||||
<% foreach(ColumnSchema p in Table.Columns) {
|
||||
|
||||
%>
|
||||
/// <summary>
|
||||
/// <%=p.Description %>
|
||||
/// </summary>
|
||||
public <%= p.SystemType.ToNullableType(p.AllowDBNull == true) %> <%= p.Name%> { get; set; }
|
||||
<% } %>
|
||||
|
||||
//todo:根据自己的业务场景添加需要的字段
|
||||
<%
|
||||
if(Table.Name.Contains("Tbl") && (!Table.Name.Contains("Dtbl")) && this.HeaderModel){
|
||||
var dtblName = Table.Name.Replace("Tbl","Dtbl"); //明细表的表名
|
||||
%>
|
||||
public List<AddOrUpdate<%=dtblName%>Req> <%=dtblName%>Reqs { get; set; }
|
||||
<% } %>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<%--
|
||||
Name: Database Table Properties
|
||||
Author: yubaolee
|
||||
Description: Create a list of properties from a database table
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="False" Description="应用层" %>
|
||||
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
namespace OpenAuth.App.Request
|
||||
{
|
||||
public class Query<%=ModuleName%>ListReq : PageReq
|
||||
{
|
||||
//todo:根据自己的业务场景添加需要的字段
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %>
|
||||
|
||||
<%@ Assembly Src="../Internal/Model.cs" %>
|
||||
<%@ Assembly Src="../Internal/Extensions.cs" %>
|
||||
|
||||
<%@ Import Namespace="System.Collections.Generic" %>
|
||||
<%@ Import Namespace="System.Linq" %>
|
||||
<%@ Import Namespace="System.Text" %>
|
||||
<%@ Import Namespace="System.Text.RegularExpressions" %>
|
||||
|
||||
<%@ Import Namespace="SchemaMapper" %>
|
||||
|
||||
<%@ Property Name="WholeDb"
|
||||
Type="System.Boolean"
|
||||
Category="1.Database"
|
||||
Default="true"
|
||||
Description="是否为整个数据库" %>
|
||||
|
||||
<%@ Property Name="SourceDatabase"
|
||||
Type="SchemaExplorer.DatabaseSchema"
|
||||
Category="1.Database"
|
||||
Description="The source database." %>
|
||||
|
||||
<%@ Property Name="SourceTables"
|
||||
Type="SchemaExplorer.TableSchemaCollection"
|
||||
Category="1.Database" Description="选择部分表" %>
|
||||
|
||||
<%@ Property Name="ContextNamespace" Type="System.String" %>
|
||||
<%@ Property Name="EntityNamespace" Type="System.String" %>
|
||||
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using <%= EntityNamespace %>;
|
||||
|
||||
namespace <%= ContextNamespace %>
|
||||
{
|
||||
<%
|
||||
string dbContextName;
|
||||
if(WholeDb){
|
||||
dbContextName = SourceDatabase.Name.ToSafeName();
|
||||
}
|
||||
else{
|
||||
dbContextName = SourceTables.First().Database.Name.ToSafeName();
|
||||
}
|
||||
dbContextName = StringUtil.ToPascalCase(dbContextName);
|
||||
Response.WriteLine(" public partial class "+ dbContextName +"Context: DbContext");
|
||||
|
||||
%>
|
||||
{
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
//当主键为联合主键时,需要把这里的内容拷贝到对应的位置
|
||||
<%
|
||||
TableSchemaCollection tables;
|
||||
if(WholeDb){
|
||||
tables = SourceDatabase.Tables;
|
||||
}
|
||||
else{
|
||||
tables = SourceTables;
|
||||
}
|
||||
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
if(table.PrimaryKeys.Count <=1) continue;
|
||||
var keys = string.Join(",", table.Columns.Where(u=>u.IsPrimaryKeyMember==true)
|
||||
.Select(u =>"c."+u.Name));
|
||||
Response.WriteLine(" modelBuilder.Entity<"+table.Name+">()");
|
||||
Response.WriteLine(" .HasKey(c => new { "+keys+" });");
|
||||
}
|
||||
%>
|
||||
}
|
||||
|
||||
<%
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
Response.WriteLine(" public virtual DbSet<"+table.Name+"> "+StringUtil.ToPascalCase(StringUtil.ToPlural(table.Name))+" { get; set; }");
|
||||
}
|
||||
%>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %>
|
||||
|
||||
<%@ Assembly Src="../Internal/Model.cs" %>
|
||||
<%@ Assembly Src="../Internal/Extensions.cs" %>
|
||||
|
||||
<%@ Import Namespace="System.Collections.Generic" %>
|
||||
<%@ Import Namespace="System.Linq" %>
|
||||
<%@ Import Namespace="System.Text" %>
|
||||
<%@ Import Namespace="System.Text.RegularExpressions" %>
|
||||
|
||||
<%@ Import Namespace="SchemaMapper" %>
|
||||
|
||||
<%@ Property Name="Table"
|
||||
Type="SchemaExplorer.TableSchema" %>
|
||||
|
||||
<%@ Property Name="EntityNamespace"
|
||||
Type="System.String" %>
|
||||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a CodeSmith Template.
|
||||
//
|
||||
// DO NOT MODIFY contents of this file. Changes to this
|
||||
// file will be lost if the code is regenerated.
|
||||
// Author:Yubao Li
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
using OpenAuth.Repository.Core;
|
||||
|
||||
namespace <%= EntityNamespace %>
|
||||
{
|
||||
/// <summary>
|
||||
/// <%= Table.Description %>
|
||||
/// </summary>
|
||||
[Table("<%= Table.Name%>")]
|
||||
public partial class <%= Table.Name %> : StringEntity
|
||||
{
|
||||
public <%= Table.Name %>()
|
||||
{
|
||||
<% foreach(ColumnSchema p in Table.Columns) {
|
||||
if(p.IsPrimaryKeyMember) continue;
|
||||
string type = p.SystemType.ToNullableType(p.AllowDBNull == true);
|
||||
if(type =="int" || type=="decimal")
|
||||
Response.WriteLine(" this."+p.Name+"= 0;");
|
||||
else if(type =="string")
|
||||
Response.WriteLine(" this."+p.Name+"= string.Empty;");
|
||||
else if(type.ToLower().Contains("datetime"))
|
||||
Response.WriteLine(" this."+p.Name+"= DateTime.Now;");
|
||||
} // foreach %>
|
||||
}
|
||||
|
||||
|
||||
<%
|
||||
foreach(ColumnSchema p in Table.Columns) {
|
||||
if(p.IsPrimaryKeyMember) continue;
|
||||
%>
|
||||
/// <summary>
|
||||
/// <%=p.Description %>
|
||||
/// </summary>
|
||||
[Description("<%=p.Description%>")]
|
||||
<%if(p.Name.LastIndexOf("Id") != -1){%>
|
||||
[Browsable(false)]
|
||||
<%}%>
|
||||
<%if(p.DataType == DbType.Byte){%>
|
||||
public bool <%= p.Name%> { get; set; }
|
||||
<%}else{%>
|
||||
public <%= p.SystemType.ToNullableType(p.AllowDBNull == true) %> <%= p.Name%> { get; set; }
|
||||
<%}%>
|
||||
<% } // foreach %>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CodeSmith.Engine;
|
||||
|
||||
namespace SchemaMapper
|
||||
{
|
||||
public enum CodeLanguage
|
||||
{
|
||||
CSharp,
|
||||
VisualBasic
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
private static readonly HashSet<string> _csharpKeywords;
|
||||
private static readonly HashSet<string> _visualBasicKeywords;
|
||||
private static readonly Dictionary<string, string> _csharpTypeAlias;
|
||||
|
||||
static Extensions()
|
||||
{
|
||||
_csharpKeywords = new HashSet<string>(StringComparer.Ordinal)
|
||||
{
|
||||
"as", "do", "if", "in", "is",
|
||||
"for", "int", "new", "out", "ref", "try",
|
||||
"base", "bool", "byte", "case", "char", "else", "enum", "goto", "lock", "long", "null", "this", "true", "uint", "void",
|
||||
"break", "catch", "class", "const", "event", "false", "fixed", "float", "sbyte", "short", "throw", "ulong", "using", "while",
|
||||
"double", "extern", "object", "params", "public", "return", "sealed", "sizeof", "static", "string", "struct", "switch", "typeof", "unsafe", "ushort",
|
||||
"checked", "decimal", "default", "finally", "foreach", "private", "virtual",
|
||||
"abstract", "continue", "delegate", "explicit", "implicit", "internal", "operator", "override", "readonly", "volatile",
|
||||
"__arglist", "__makeref", "__reftype", "interface", "namespace", "protected", "unchecked",
|
||||
"__refvalue", "stackalloc"
|
||||
};
|
||||
|
||||
_visualBasicKeywords = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"as", "do", "if", "in", "is", "me", "of", "on", "or", "to",
|
||||
"and", "dim", "end", "for", "get", "let", "lib", "mod", "new", "not", "rem", "set", "sub", "try", "xor",
|
||||
"ansi", "auto", "byte", "call", "case", "cdbl", "cdec", "char", "cint", "clng", "cobj", "csng", "cstr", "date", "each", "else",
|
||||
"enum", "exit", "goto", "like", "long", "loop", "next", "step", "stop", "then", "true", "wend", "when", "with",
|
||||
"alias", "byref", "byval", "catch", "cbool", "cbyte", "cchar", "cdate", "class", "const", "ctype", "cuint", "culng", "endif", "erase", "error",
|
||||
"event", "false", "gosub", "isnot", "redim", "sbyte", "short", "throw", "ulong", "until", "using", "while",
|
||||
"csbyte", "cshort", "double", "elseif", "friend", "global", "module", "mybase", "object", "option", "orelse", "public", "resume", "return", "select", "shared",
|
||||
"single", "static", "string", "typeof", "ushort",
|
||||
"andalso", "boolean", "cushort", "decimal", "declare", "default", "finally", "gettype", "handles", "imports", "integer", "myclass", "nothing", "partial", "private", "shadows",
|
||||
"trycast", "unicode", "variant",
|
||||
"assembly", "continue", "delegate", "function", "inherits", "operator", "optional", "preserve", "property", "readonly", "synclock", "uinteger", "widening",
|
||||
"addressof", "interface", "namespace", "narrowing", "overloads", "overrides", "protected", "structure", "writeonly",
|
||||
"addhandler", "directcast", "implements", "paramarray", "raiseevent", "withevents",
|
||||
"mustinherit", "overridable",
|
||||
"mustoverride",
|
||||
"removehandler",
|
||||
"class_finalize", "notinheritable", "notoverridable",
|
||||
"class_initialize"
|
||||
};
|
||||
|
||||
_csharpTypeAlias = new Dictionary<string, string>(16)
|
||||
{
|
||||
{"System.Int16", "short"},
|
||||
{"System.Int32", "int"},
|
||||
{"System.Int64", "long"},
|
||||
{"System.String", "string"},
|
||||
{"System.Object", "object"},
|
||||
{"System.Boolean", "bool"},
|
||||
{"System.Void", "void"},
|
||||
{"System.Char", "char"},
|
||||
{"System.Byte", "byte"},
|
||||
{"System.UInt16", "ushort"},
|
||||
{"System.UInt32", "uint"},
|
||||
{"System.UInt64", "ulong"},
|
||||
{"System.SByte", "sbyte"},
|
||||
{"System.Single", "float"},
|
||||
{"System.Double", "double"},
|
||||
{"System.Decimal", "decimal"}
|
||||
};
|
||||
}
|
||||
|
||||
public static string ToCamelCase(this string name)
|
||||
{
|
||||
return StringUtil.ToCamelCase(name);
|
||||
}
|
||||
|
||||
public static string ToPascalCase(this string name)
|
||||
{
|
||||
return StringUtil.ToPascalCase(name);
|
||||
}
|
||||
|
||||
|
||||
public static string ToFieldName(this string name)
|
||||
{
|
||||
return "_" + StringUtil.ToCamelCase(name);
|
||||
}
|
||||
|
||||
public static string MakeUnique(this string name, Func<string, bool> exists)
|
||||
{
|
||||
string uniqueName = name;
|
||||
int count = 1;
|
||||
|
||||
while (exists(uniqueName))
|
||||
uniqueName = string.Concat(name, count++);
|
||||
|
||||
return uniqueName;
|
||||
}
|
||||
|
||||
public static bool IsKeyword(this string text, CodeLanguage language = CodeLanguage.CSharp)
|
||||
{
|
||||
return language == CodeLanguage.VisualBasic
|
||||
? _visualBasicKeywords.Contains(text)
|
||||
: _csharpKeywords.Contains(text);
|
||||
}
|
||||
|
||||
public static string ToSafeName(this string name, CodeLanguage language = CodeLanguage.CSharp)
|
||||
{
|
||||
if (!name.IsKeyword(language))
|
||||
return name;
|
||||
|
||||
return language == CodeLanguage.VisualBasic
|
||||
? string.Format("[{0}]", name)
|
||||
: "@" + name;
|
||||
}
|
||||
|
||||
public static string ToType(this Type type, CodeLanguage language = CodeLanguage.CSharp)
|
||||
{
|
||||
return ToType(type.FullName, language);
|
||||
}
|
||||
|
||||
public static string ToType(this string type, CodeLanguage language = CodeLanguage.CSharp)
|
||||
{
|
||||
if (type == "System.Xml.XmlDocument")
|
||||
type = "System.String";
|
||||
|
||||
string t;
|
||||
if (language == CodeLanguage.CSharp && _csharpTypeAlias.TryGetValue(type, out t))
|
||||
return t;
|
||||
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public static string ToNullableType(this Type type, bool isNullable = false, CodeLanguage language = CodeLanguage.CSharp)
|
||||
{
|
||||
return ToNullableType(type.FullName, isNullable, language);
|
||||
}
|
||||
|
||||
public static string ToNullableType(this string type, bool isNullable = false, CodeLanguage language = CodeLanguage.CSharp)
|
||||
{
|
||||
bool isValueType = type.IsValueType();
|
||||
|
||||
type = type.ToType(language);
|
||||
|
||||
if (!isValueType || !isNullable)
|
||||
return type;
|
||||
|
||||
return language == CodeLanguage.VisualBasic
|
||||
? string.Format("Nullable(Of {0})", type)
|
||||
: type + "?";
|
||||
}
|
||||
|
||||
public static bool IsValueType(this string type)
|
||||
{
|
||||
if (!type.StartsWith("System."))
|
||||
return false;
|
||||
|
||||
var t = Type.GetType(type, false);
|
||||
return t != null && t.IsValueType;
|
||||
}
|
||||
|
||||
public static string ToDelimitedString(this IEnumerable<string> values, string delimiter, string format = null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var i in values)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append(delimiter);
|
||||
|
||||
if (string.IsNullOrEmpty(format))
|
||||
sb.Append(i);
|
||||
else
|
||||
sb.AppendFormat(format, i);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,837 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using CodeSmith.Engine;
|
||||
using SchemaExplorer;
|
||||
|
||||
namespace SchemaMapper
|
||||
{
|
||||
public enum TableNaming
|
||||
{
|
||||
Mixed = 0,
|
||||
Plural = 1,
|
||||
Singular = 2
|
||||
}
|
||||
|
||||
public enum EntityNaming
|
||||
{
|
||||
Preserve = 0,
|
||||
Plural = 1,
|
||||
Singular = 2
|
||||
}
|
||||
|
||||
public enum RelationshipNaming
|
||||
{
|
||||
None = 0,
|
||||
Plural = 1,
|
||||
ListSuffix = 2
|
||||
}
|
||||
|
||||
public enum ContextNaming
|
||||
{
|
||||
Preserve = 0,
|
||||
Plural = 1,
|
||||
TableSuffix = 2
|
||||
}
|
||||
|
||||
public class GeneratorSettings
|
||||
{
|
||||
public GeneratorSettings()
|
||||
{
|
||||
RelationshipNaming = RelationshipNaming.ListSuffix;
|
||||
EntityNaming = EntityNaming.Singular;
|
||||
TableNaming = TableNaming.Singular;
|
||||
CleanExpressions = new List<string> { @"^\d+" };
|
||||
IgnoreExpressions = new List<string>();
|
||||
}
|
||||
|
||||
public TableNaming TableNaming { get; set; }
|
||||
|
||||
public EntityNaming EntityNaming { get; set; }
|
||||
|
||||
public RelationshipNaming RelationshipNaming { get; set; }
|
||||
|
||||
public ContextNaming ContextNaming { get; set; }
|
||||
|
||||
public List<string> IgnoreExpressions { get; set; }
|
||||
|
||||
public List<string> CleanExpressions { get; set; }
|
||||
|
||||
public bool InclusionMode { get; set; }
|
||||
|
||||
public bool IsIgnored(string name)
|
||||
{
|
||||
if (IgnoreExpressions.Count == 0)
|
||||
return false;
|
||||
|
||||
bool isMatch = IgnoreExpressions.Any(regex => Regex.IsMatch(name, regex));
|
||||
|
||||
return InclusionMode ? !isMatch : isMatch;
|
||||
}
|
||||
|
||||
public string CleanName(string name)
|
||||
{
|
||||
if (CleanExpressions.Count == 0)
|
||||
return name;
|
||||
|
||||
foreach (var regex in CleanExpressions.Where(r => !string.IsNullOrEmpty(r)))
|
||||
if (Regex.IsMatch(name, regex))
|
||||
return Regex.Replace(name, regex, "");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public string RelationshipName(string name)
|
||||
{
|
||||
if (RelationshipNaming == RelationshipNaming.None)
|
||||
return name;
|
||||
|
||||
if (RelationshipNaming == RelationshipNaming.ListSuffix)
|
||||
return name + "List";
|
||||
|
||||
return StringUtil.ToPascalCase(StringUtil.ToPlural(name));
|
||||
}
|
||||
|
||||
public string ContextName(string name)
|
||||
{
|
||||
if (ContextNaming == ContextNaming.Preserve)
|
||||
return name;
|
||||
|
||||
if (ContextNaming == ContextNaming.TableSuffix)
|
||||
return name + "Table";
|
||||
|
||||
return StringUtil.ToPascalCase(StringUtil.ToPlural(name));
|
||||
}
|
||||
|
||||
public string EntityName(string name)
|
||||
{
|
||||
if (TableNaming != TableNaming.Plural && EntityNaming == EntityNaming.Plural)
|
||||
name = StringUtil.ToPlural(name);
|
||||
else if (TableNaming != TableNaming.Singular && EntityNaming == EntityNaming.Singular)
|
||||
name = StringUtil.ToSingular(name);
|
||||
|
||||
return StringUtil.ToPascalCase(name);
|
||||
}
|
||||
}
|
||||
|
||||
public class SchemaItemProcessedEventArgs : EventArgs
|
||||
{
|
||||
public SchemaItemProcessedEventArgs(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
private readonly string _name;
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
}
|
||||
|
||||
public class UniqueNamer
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, HashSet<string>> _names;
|
||||
|
||||
public UniqueNamer()
|
||||
{
|
||||
_names = new ConcurrentDictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
Comparer = StringComparer.CurrentCulture;
|
||||
|
||||
// add existing
|
||||
UniqueContextName("ChangeTracker");
|
||||
UniqueContextName("Configuration");
|
||||
UniqueContextName("Database");
|
||||
UniqueContextName("InternalContext");
|
||||
}
|
||||
|
||||
public IEqualityComparer<string> Comparer { get; set; }
|
||||
|
||||
public string UniqueName(string bucketName, string name)
|
||||
{
|
||||
var hashSet = _names.GetOrAdd(bucketName, k => new HashSet<string>(Comparer));
|
||||
string result = name.MakeUnique(hashSet.Contains);
|
||||
hashSet.Add(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string UniqueClassName(string className)
|
||||
{
|
||||
const string globalClassName = "global::ClassName";
|
||||
return UniqueName(globalClassName, className);
|
||||
}
|
||||
|
||||
public string UniqueContextName(string name)
|
||||
{
|
||||
const string globalContextname = "global::ContextName";
|
||||
return UniqueName(globalContextname, name);
|
||||
}
|
||||
|
||||
public string UniqueRelationshipName(string name)
|
||||
{
|
||||
const string globalContextname = "global::RelationshipName";
|
||||
return UniqueName(globalContextname, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Generator
|
||||
{
|
||||
private readonly UniqueNamer _namer;
|
||||
|
||||
public Generator()
|
||||
{
|
||||
_settings = new GeneratorSettings();
|
||||
_namer = new UniqueNamer();
|
||||
}
|
||||
|
||||
public event EventHandler<SchemaItemProcessedEventArgs> SchemaItemProcessed;
|
||||
protected void OnSchemaItemProcessed(string name)
|
||||
{
|
||||
var handler = SchemaItemProcessed;
|
||||
if (handler == null)
|
||||
return;
|
||||
|
||||
handler(this, new SchemaItemProcessedEventArgs(name));
|
||||
}
|
||||
|
||||
private readonly GeneratorSettings _settings;
|
||||
public GeneratorSettings Settings
|
||||
{
|
||||
get { return _settings; }
|
||||
}
|
||||
|
||||
//按表信息创建DbContext
|
||||
public EntityContext Generate(TableSchema tableSchema)
|
||||
{
|
||||
// only DeepLoad when in ignore mode
|
||||
tableSchema.DeepLoad = !Settings.InclusionMode;
|
||||
|
||||
var entityContext = new EntityContext();
|
||||
entityContext.DatabaseName = tableSchema.Database.Name;
|
||||
|
||||
string dataContextName = StringUtil.ToPascalCase(tableSchema.Database.Name) + "Context";
|
||||
dataContextName = _namer.UniqueClassName(dataContextName);
|
||||
|
||||
entityContext.ClassName = dataContextName;
|
||||
|
||||
GetEntity(entityContext, tableSchema);
|
||||
|
||||
|
||||
return entityContext;
|
||||
}
|
||||
|
||||
//按数据库连接信息创建DbContext
|
||||
public EntityContext Generate(DatabaseSchema databaseSchema)
|
||||
{
|
||||
// only DeepLoad when in ignore mode
|
||||
databaseSchema.DeepLoad = !Settings.InclusionMode;
|
||||
|
||||
var entityContext = new EntityContext();
|
||||
entityContext.DatabaseName = databaseSchema.Name;
|
||||
|
||||
string dataContextName = StringUtil.ToPascalCase(databaseSchema.Name) + "Context";
|
||||
dataContextName = _namer.UniqueClassName(dataContextName);
|
||||
|
||||
entityContext.ClassName = dataContextName;
|
||||
|
||||
foreach (TableSchema t in databaseSchema.Tables)
|
||||
{
|
||||
if (Settings.IsIgnored(t.FullName))
|
||||
{
|
||||
Debug.WriteLine("Skipping Table: " + t.FullName);
|
||||
}
|
||||
else if (IsManyToMany(t))
|
||||
{
|
||||
CreateManyToMany(entityContext, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("Getting Table Schema: " + t.FullName);
|
||||
GetEntity(entityContext, t);
|
||||
}
|
||||
|
||||
OnSchemaItemProcessed(t.FullName);
|
||||
}
|
||||
|
||||
return entityContext;
|
||||
}
|
||||
|
||||
//根据DbContext和tableSchema获取实体
|
||||
public Entity GetEntity(EntityContext entityContext, TableSchema tableSchema, bool processRelationships = true, bool processMethods = true)
|
||||
{
|
||||
string key = tableSchema.FullName;
|
||||
|
||||
Entity entity = entityContext.Entities.ByTable(key)
|
||||
?? CreateEntity(entityContext, tableSchema);
|
||||
|
||||
if (!entity.Properties.IsProcessed)
|
||||
CreateProperties(entity, tableSchema);
|
||||
|
||||
if (processRelationships && !entity.Relationships.IsProcessed)
|
||||
CreateRelationships(entityContext, entity, tableSchema);
|
||||
|
||||
if (processMethods && !entity.Methods.IsProcessed)
|
||||
CreateMethods(entity, tableSchema);
|
||||
|
||||
entity.IsProcessed = true;
|
||||
return entity;
|
||||
}
|
||||
|
||||
private Entity CreateEntity(EntityContext entityContext, TableSchema tableSchema)
|
||||
{
|
||||
var entity = new Entity
|
||||
{
|
||||
FullName = tableSchema.FullName,
|
||||
TableName = tableSchema.Name,
|
||||
TableSchema = tableSchema.Owner,
|
||||
Description = tableSchema.Description
|
||||
};
|
||||
|
||||
string className = ToClassName(tableSchema.Name);
|
||||
className = _namer.UniqueClassName(className);
|
||||
|
||||
string mappingName = className + "Map";
|
||||
mappingName = _namer.UniqueClassName(mappingName);
|
||||
|
||||
string contextName = Settings.ContextName(className);
|
||||
contextName = ToPropertyName(entityContext.ClassName, contextName);
|
||||
contextName = _namer.UniqueContextName(contextName);
|
||||
|
||||
entity.ClassName = className;
|
||||
entity.ContextName = contextName;
|
||||
entity.MappingName = mappingName;
|
||||
|
||||
entityContext.Entities.Add(entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建实体的属性
|
||||
/// </summary>
|
||||
private void CreateProperties(Entity entity, TableSchema tableSchema)
|
||||
{
|
||||
foreach (ColumnSchema columnSchema in tableSchema.Columns)
|
||||
{
|
||||
// skip unsupported type
|
||||
if (columnSchema.NativeType.Equals("hierarchyid", StringComparison.OrdinalIgnoreCase)
|
||||
|| columnSchema.NativeType.Equals("sql_variant", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Debug.WriteLine(string.Format("Skipping column '{0}' because it has an unsupported db type '{1}'.",
|
||||
columnSchema.Name, columnSchema.NativeType));
|
||||
continue;
|
||||
}
|
||||
|
||||
Property property = entity.Properties.ByColumn(columnSchema.Name);
|
||||
|
||||
if (property == null)
|
||||
{
|
||||
property = new Property { ColumnName = columnSchema.Name };
|
||||
entity.Properties.Add(property);
|
||||
}
|
||||
|
||||
string propertyName = ToPropertyName(entity.ClassName, columnSchema.Name);
|
||||
propertyName = _namer.UniqueName(entity.ClassName, propertyName);
|
||||
|
||||
property.PropertyName = propertyName;
|
||||
|
||||
property.DataType = columnSchema.DataType;
|
||||
property.SystemType = columnSchema.SystemType;
|
||||
property.NativeType = columnSchema.NativeType;
|
||||
property.Description = columnSchema.Description;
|
||||
|
||||
property.IsPrimaryKey = columnSchema.IsPrimaryKeyMember;
|
||||
property.IsForeignKey = columnSchema.IsForeignKeyMember;
|
||||
property.IsNullable = columnSchema.AllowDBNull;
|
||||
|
||||
property.IsIdentity = IsIdentity(columnSchema);
|
||||
property.IsRowVersion = IsRowVersion(columnSchema);
|
||||
property.IsAutoGenerated = IsDbGenerated(columnSchema);
|
||||
|
||||
if (columnSchema.IsUnique)
|
||||
property.IsUnique = columnSchema.IsUnique;
|
||||
|
||||
if (property.SystemType == typeof(string)
|
||||
|| property.SystemType == typeof(byte[]))
|
||||
{
|
||||
property.MaxLength = columnSchema.Size;
|
||||
}
|
||||
|
||||
if (property.SystemType == typeof(float)
|
||||
|| property.SystemType == typeof(double)
|
||||
|| property.SystemType == typeof(decimal))
|
||||
{
|
||||
property.Precision = columnSchema.Precision;
|
||||
property.Scale = columnSchema.Scale;
|
||||
}
|
||||
|
||||
property.IsProcessed = true;
|
||||
}
|
||||
|
||||
entity.Properties.IsProcessed = true;
|
||||
}
|
||||
|
||||
|
||||
private void CreateRelationships(EntityContext entityContext, Entity entity, TableSchema tableSchema)
|
||||
{
|
||||
foreach (TableKeySchema tableKey in tableSchema.ForeignKeys)
|
||||
{
|
||||
if (Settings.IsIgnored(tableKey.ForeignKeyTable.FullName)
|
||||
|| Settings.IsIgnored(tableKey.PrimaryKeyTable.FullName))
|
||||
{
|
||||
Debug.WriteLine("Skipping relationship '{0}' because table '{1}' or '{2}' is ignored.",
|
||||
tableKey.FullName, tableKey.ForeignKeyTable.FullName, tableKey.PrimaryKeyTable.FullName);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
CreateRelationship(entityContext, entity, tableKey);
|
||||
}
|
||||
|
||||
entity.Relationships.IsProcessed = true;
|
||||
}
|
||||
|
||||
private void CreateRelationship(EntityContext entityContext, Entity foreignEntity, TableKeySchema tableKeySchema)
|
||||
{
|
||||
Entity primaryEntity = GetEntity(entityContext, tableKeySchema.PrimaryKeyTable, false, false);
|
||||
|
||||
string primaryName = primaryEntity.ClassName;
|
||||
string foreignName = foreignEntity.ClassName;
|
||||
|
||||
string relationshipName = tableKeySchema.Name;
|
||||
relationshipName = _namer.UniqueRelationshipName(relationshipName);
|
||||
|
||||
bool isCascadeDelete = IsCascadeDelete(tableKeySchema);
|
||||
bool foreignMembersRequired;
|
||||
bool primaryMembersRequired;
|
||||
|
||||
var foreignMembers = GetKeyMembers(foreignEntity, tableKeySchema.ForeignKeyMemberColumns, tableKeySchema.Name, out foreignMembersRequired);
|
||||
var primaryMembers = GetKeyMembers(primaryEntity, tableKeySchema.PrimaryKeyMemberColumns, tableKeySchema.Name, out primaryMembersRequired);
|
||||
|
||||
Relationship foreignRelationship = foreignEntity.Relationships
|
||||
.FirstOrDefault(r => r.RelationshipName == relationshipName && r.IsForeignKey);
|
||||
|
||||
if (foreignRelationship == null)
|
||||
{
|
||||
foreignRelationship = new Relationship { RelationshipName = relationshipName };
|
||||
foreignEntity.Relationships.Add(foreignRelationship);
|
||||
}
|
||||
foreignRelationship.IsMapped = true;
|
||||
foreignRelationship.IsForeignKey = true;
|
||||
foreignRelationship.ThisCardinality = foreignMembersRequired ? Cardinality.One : Cardinality.ZeroOrOne;
|
||||
foreignRelationship.ThisEntity = foreignName;
|
||||
foreignRelationship.ThisProperties = new List<string>(foreignMembers);
|
||||
foreignRelationship.OtherEntity = primaryName;
|
||||
foreignRelationship.OtherProperties = new List<string>(primaryMembers);
|
||||
foreignRelationship.CascadeDelete = isCascadeDelete;
|
||||
|
||||
string prefix = GetMemberPrefix(foreignRelationship, primaryName, foreignName);
|
||||
|
||||
string foreignPropertyName = ToPropertyName(foreignEntity.ClassName, prefix + primaryName);
|
||||
foreignPropertyName = _namer.UniqueName(foreignEntity.ClassName, foreignPropertyName);
|
||||
foreignRelationship.ThisPropertyName = foreignPropertyName;
|
||||
|
||||
// add reverse
|
||||
Relationship primaryRelationship = primaryEntity.Relationships
|
||||
.FirstOrDefault(r => r.RelationshipName == relationshipName && r.IsForeignKey == false);
|
||||
|
||||
if (primaryRelationship == null)
|
||||
{
|
||||
primaryRelationship = new Relationship { RelationshipName = relationshipName };
|
||||
primaryEntity.Relationships.Add(primaryRelationship);
|
||||
}
|
||||
|
||||
primaryRelationship.IsMapped = false;
|
||||
primaryRelationship.IsForeignKey = false;
|
||||
primaryRelationship.ThisEntity = primaryName;
|
||||
primaryRelationship.ThisProperties = new List<string>(primaryMembers);
|
||||
primaryRelationship.OtherEntity = foreignName;
|
||||
primaryRelationship.OtherProperties = new List<string>(foreignMembers);
|
||||
primaryRelationship.CascadeDelete = isCascadeDelete;
|
||||
|
||||
bool isOneToOne = IsOneToOne(tableKeySchema, foreignRelationship);
|
||||
|
||||
if (isOneToOne)
|
||||
primaryRelationship.ThisCardinality = primaryMembersRequired ? Cardinality.One : Cardinality.ZeroOrOne;
|
||||
else
|
||||
primaryRelationship.ThisCardinality = Cardinality.Many;
|
||||
|
||||
string primaryPropertyName = prefix + foreignName;
|
||||
if (!isOneToOne)
|
||||
primaryPropertyName = Settings.RelationshipName(primaryPropertyName);
|
||||
|
||||
primaryPropertyName = ToPropertyName(primaryEntity.ClassName, primaryPropertyName);
|
||||
primaryPropertyName = _namer.UniqueName(primaryEntity.ClassName, primaryPropertyName);
|
||||
|
||||
primaryRelationship.ThisPropertyName = primaryPropertyName;
|
||||
|
||||
foreignRelationship.OtherPropertyName = primaryRelationship.ThisPropertyName;
|
||||
foreignRelationship.OtherCardinality = primaryRelationship.ThisCardinality;
|
||||
|
||||
primaryRelationship.OtherPropertyName = foreignRelationship.ThisPropertyName;
|
||||
primaryRelationship.OtherCardinality = foreignRelationship.ThisCardinality;
|
||||
|
||||
foreignRelationship.IsProcessed = true;
|
||||
primaryRelationship.IsProcessed = true;
|
||||
}
|
||||
|
||||
private void CreateManyToMany(EntityContext entityContext, TableSchema joinTable)
|
||||
{
|
||||
if (joinTable.ForeignKeys.Count != 2)
|
||||
return;
|
||||
|
||||
var joinTableName = joinTable.Name;
|
||||
var joinSchemaName = joinTable.Owner;
|
||||
|
||||
// first fkey is always left, second fkey is right
|
||||
var leftForeignKey = joinTable.ForeignKeys[0];
|
||||
var leftTable = leftForeignKey.PrimaryKeyTable;
|
||||
var joinLeftColumn = leftForeignKey.ForeignKeyMemberColumns.Select(c => c.Name).ToList();
|
||||
var leftEntity = GetEntity(entityContext, leftTable, false, false);
|
||||
|
||||
var rightForeignKey = joinTable.ForeignKeys[1];
|
||||
var rightTable = rightForeignKey.PrimaryKeyTable;
|
||||
var joinRightColumn = rightForeignKey.ForeignKeyMemberColumns.Select(c => c.Name).ToList();
|
||||
var rightEntity = GetEntity(entityContext, rightTable, false, false);
|
||||
|
||||
string leftPropertyName = Settings.RelationshipName(rightEntity.ClassName);
|
||||
leftPropertyName = _namer.UniqueName(leftEntity.ClassName, leftPropertyName);
|
||||
|
||||
string rightPropertyName = Settings.RelationshipName(leftEntity.ClassName);
|
||||
rightPropertyName = _namer.UniqueName(rightEntity.ClassName, rightPropertyName);
|
||||
|
||||
string relationshipName = string.Format("{0}|{1}",
|
||||
leftForeignKey.Name,
|
||||
rightForeignKey.Name);
|
||||
|
||||
relationshipName = _namer.UniqueRelationshipName(relationshipName);
|
||||
|
||||
var left = new Relationship { RelationshipName = relationshipName };
|
||||
left.IsForeignKey = false;
|
||||
left.IsMapped = true;
|
||||
|
||||
left.ThisCardinality = Cardinality.Many;
|
||||
left.ThisEntity = leftEntity.ClassName;
|
||||
left.ThisPropertyName = leftPropertyName;
|
||||
|
||||
left.OtherCardinality = Cardinality.Many;
|
||||
left.OtherEntity = rightEntity.ClassName;
|
||||
left.OtherPropertyName = rightPropertyName;
|
||||
|
||||
left.JoinTable = joinTableName;
|
||||
left.JoinSchema = joinSchemaName;
|
||||
left.JoinThisColumn = new List<string>(joinLeftColumn);
|
||||
left.JoinOtherColumn = new List<string>(joinRightColumn);
|
||||
|
||||
leftEntity.Relationships.Add(left);
|
||||
|
||||
var right = new Relationship { RelationshipName = relationshipName };
|
||||
right.IsForeignKey = false;
|
||||
right.IsMapped = false;
|
||||
|
||||
right.ThisCardinality = Cardinality.Many;
|
||||
right.ThisEntity = rightEntity.ClassName;
|
||||
right.ThisPropertyName = rightPropertyName;
|
||||
|
||||
right.OtherCardinality = Cardinality.Many;
|
||||
right.OtherEntity = leftEntity.ClassName;
|
||||
right.OtherPropertyName = leftPropertyName;
|
||||
|
||||
right.JoinTable = joinTableName;
|
||||
right.JoinSchema = joinSchemaName;
|
||||
right.JoinThisColumn = new List<string>(joinRightColumn);
|
||||
right.JoinOtherColumn = new List<string>(joinLeftColumn);
|
||||
|
||||
rightEntity.Relationships.Add(right);
|
||||
}
|
||||
|
||||
|
||||
private void CreateMethods(Entity entity, TableSchema tableSchema)
|
||||
{
|
||||
if (tableSchema.HasPrimaryKey)
|
||||
{
|
||||
var method = GetMethodFromColumns(entity, tableSchema.PrimaryKey.MemberColumns);
|
||||
if (method != null)
|
||||
{
|
||||
method.IsKey = true;
|
||||
method.SourceName = tableSchema.PrimaryKey.FullName;
|
||||
|
||||
if (!entity.Methods.Any(m => m.NameSuffix == method.NameSuffix))
|
||||
entity.Methods.Add(method);
|
||||
}
|
||||
}
|
||||
|
||||
GetIndexMethods(entity, tableSchema);
|
||||
GetForeignKeyMethods(entity, tableSchema);
|
||||
|
||||
entity.Methods.IsProcessed = true;
|
||||
}
|
||||
|
||||
private static void GetForeignKeyMethods(Entity entity, TableSchema table)
|
||||
{
|
||||
var columns = new List<ColumnSchema>();
|
||||
|
||||
foreach (ColumnSchema column in table.ForeignKeyColumns)
|
||||
{
|
||||
columns.Add(column);
|
||||
|
||||
Method method = GetMethodFromColumns(entity, columns);
|
||||
if (method != null && !entity.Methods.Any(m => m.NameSuffix == method.NameSuffix))
|
||||
entity.Methods.Add(method);
|
||||
|
||||
columns.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetIndexMethods(Entity entity, TableSchema table)
|
||||
{
|
||||
foreach (IndexSchema index in table.Indexes)
|
||||
{
|
||||
Method method = GetMethodFromColumns(entity, index.MemberColumns);
|
||||
if (method == null)
|
||||
continue;
|
||||
|
||||
method.SourceName = index.FullName;
|
||||
method.IsUnique = index.IsUnique;
|
||||
method.IsIndex = true;
|
||||
|
||||
if (!entity.Methods.Any(m => m.NameSuffix == method.NameSuffix))
|
||||
entity.Methods.Add(method);
|
||||
}
|
||||
}
|
||||
|
||||
private static Method GetMethodFromColumns(Entity entity, IEnumerable<ColumnSchema> columns)
|
||||
{
|
||||
var method = new Method();
|
||||
string methodName = string.Empty;
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
var property = entity.Properties.ByColumn(column.Name);
|
||||
if (property == null)
|
||||
continue;
|
||||
|
||||
method.Properties.Add(property);
|
||||
methodName += property.PropertyName;
|
||||
}
|
||||
|
||||
if (method.Properties.Count == 0)
|
||||
return null;
|
||||
|
||||
method.NameSuffix = methodName;
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
private static List<string> GetKeyMembers(Entity entity, IEnumerable<MemberColumnSchema> members, string name, out bool isRequired)
|
||||
{
|
||||
var keyMembers = new List<string>();
|
||||
isRequired = false;
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
var property = entity.Properties.ByColumn(member.Name);
|
||||
|
||||
if (property == null)
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Could not find column {0} for relationship {1}.",
|
||||
member.Name,
|
||||
name));
|
||||
|
||||
if (!isRequired)
|
||||
isRequired = property.IsRequired;
|
||||
|
||||
keyMembers.Add(property.PropertyName);
|
||||
}
|
||||
|
||||
return keyMembers;
|
||||
}
|
||||
|
||||
private static string GetMemberPrefix(Relationship relationship, string primaryClass, string foreignClass)
|
||||
{
|
||||
string thisKey = relationship.ThisProperties.FirstOrDefault() ?? string.Empty;
|
||||
string otherKey = relationship.OtherProperties.FirstOrDefault() ?? string.Empty;
|
||||
|
||||
bool isSameName = thisKey.Equals(otherKey, StringComparison.OrdinalIgnoreCase);
|
||||
isSameName = (isSameName || thisKey.Equals(primaryClass + otherKey, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
string prefix = string.Empty;
|
||||
if (isSameName)
|
||||
return prefix;
|
||||
|
||||
prefix = thisKey.Replace(otherKey, "");
|
||||
prefix = prefix.Replace(primaryClass, "");
|
||||
prefix = prefix.Replace(foreignClass, "");
|
||||
prefix = Regex.Replace(prefix, @"(_ID|_id|_Id|\.ID|\.id|\.Id|ID|Id)$", "");
|
||||
prefix = Regex.Replace(prefix, @"^\d", "");
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
private static bool IsOneToOne(TableKeySchema tableKeySchema, Relationship foreignRelationship)
|
||||
{
|
||||
bool isFkeyPkey = tableKeySchema.ForeignKeyTable.HasPrimaryKey
|
||||
&& tableKeySchema.ForeignKeyTable.PrimaryKey != null
|
||||
&& tableKeySchema.ForeignKeyTable.PrimaryKey.MemberColumns.Count == 1
|
||||
&& tableKeySchema.ForeignKeyTable.PrimaryKey.MemberColumns.Contains(
|
||||
foreignRelationship.ThisProperties.FirstOrDefault());
|
||||
|
||||
if (isFkeyPkey)
|
||||
return true;
|
||||
|
||||
// if f.key is unique
|
||||
return tableKeySchema.ForeignKeyMemberColumns.All(column => column.IsUnique);
|
||||
}
|
||||
|
||||
private static bool IsManyToMany(TableSchema tableSchema)
|
||||
{
|
||||
// 1) Table must have Two ForeignKeys.
|
||||
// 2) All columns must be either...
|
||||
// a) Member of a Foreign Key.
|
||||
// b) DbGenerated
|
||||
|
||||
if (tableSchema.Columns.Count < 2)
|
||||
return false;
|
||||
|
||||
if (tableSchema.ForeignKeyColumns.Count != 2)
|
||||
return false;
|
||||
|
||||
// all columns are fkeys
|
||||
if (tableSchema.Columns.Count == 2 &&
|
||||
tableSchema.ForeignKeyColumns.Count == 2)
|
||||
return true;
|
||||
|
||||
// check all non fkey columns to make sure db gen'd
|
||||
return tableSchema.NonForeignKeyColumns.All(c =>
|
||||
IsDbGenerated(c) || HasDefaultValue(c));
|
||||
}
|
||||
|
||||
#region Name Helpers
|
||||
private string ToClassName(string name)
|
||||
{
|
||||
name = Settings.EntityName(name);
|
||||
string legalName = ToLegalName(name);
|
||||
|
||||
return legalName;
|
||||
}
|
||||
|
||||
private string ToPropertyName(string className, string name)
|
||||
{
|
||||
string propertyName = ToLegalName(name);
|
||||
if (className.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
|
||||
propertyName += "Member";
|
||||
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
private string ToLegalName(string name)
|
||||
{
|
||||
string legalName = Settings.CleanName(name);
|
||||
legalName = StringUtil.ToPascalCase(legalName);
|
||||
|
||||
return legalName;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Column Flag Helpers
|
||||
private static bool IsCascadeDelete(SchemaObjectBase column)
|
||||
{
|
||||
bool cascadeDelete = false;
|
||||
string value;
|
||||
try
|
||||
{
|
||||
if (column.ExtendedProperties.Contains(ExtendedPropertyNames.CascadeDelete))
|
||||
{
|
||||
value = column.ExtendedProperties[ExtendedPropertyNames.CascadeDelete].Value.ToString();
|
||||
bool.TryParse(value, out cascadeDelete);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Error: " + ex.Message);
|
||||
}
|
||||
|
||||
return cascadeDelete;
|
||||
}
|
||||
|
||||
private static bool IsRowVersion(DataObjectBase column)
|
||||
{
|
||||
bool isTimeStamp = column.NativeType.Equals(
|
||||
"timestamp", StringComparison.OrdinalIgnoreCase);
|
||||
bool isRowVersion = column.NativeType.Equals(
|
||||
"rowversion", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return (isTimeStamp || isRowVersion);
|
||||
}
|
||||
|
||||
private static bool IsDbGenerated(DataObjectBase column)
|
||||
{
|
||||
if (IsRowVersion(column))
|
||||
return true;
|
||||
|
||||
if (IsIdentity(column))
|
||||
return true;
|
||||
|
||||
bool isComputed = false;
|
||||
string value;
|
||||
try
|
||||
{
|
||||
if (column.ExtendedProperties.Contains(ExtendedPropertyNames.IsComputed))
|
||||
{
|
||||
value = column.ExtendedProperties[ExtendedPropertyNames.IsComputed].Value.ToString();
|
||||
bool.TryParse(value, out isComputed);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Error: " + ex.Message);
|
||||
}
|
||||
|
||||
return isComputed;
|
||||
}
|
||||
|
||||
private static bool IsIdentity(DataObjectBase column)
|
||||
{
|
||||
string temp;
|
||||
bool isIdentity = false;
|
||||
try
|
||||
{
|
||||
if (column.ExtendedProperties.Contains(ExtendedPropertyNames.IsIdentity))
|
||||
{
|
||||
temp = column.ExtendedProperties[ExtendedPropertyNames.IsIdentity].Value.ToString();
|
||||
bool.TryParse(temp, out isIdentity);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Error: " + ex.Message);
|
||||
}
|
||||
|
||||
return isIdentity;
|
||||
}
|
||||
|
||||
private static bool HasDefaultValue(DataObjectBase column)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!column.ExtendedProperties.Contains(ExtendedPropertyNames.DefaultValue))
|
||||
return false;
|
||||
|
||||
string value = column.ExtendedProperties[ExtendedPropertyNames.DefaultValue].Value.ToString();
|
||||
return !string.IsNullOrEmpty(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Error: " + ex.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,370 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SchemaMapper
|
||||
{
|
||||
#region Base
|
||||
public enum Cardinality
|
||||
{
|
||||
ZeroOrOne,
|
||||
One,
|
||||
Many
|
||||
}
|
||||
|
||||
public class EntityBase
|
||||
{
|
||||
[XmlIgnore]
|
||||
public bool IsProcessed { get; set; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Model
|
||||
[DebuggerDisplay("Context: {ContextName}, Database: {DatabaseName}")]
|
||||
public class EntityContext : EntityBase
|
||||
{
|
||||
public EntityContext()
|
||||
{
|
||||
Entities = new EntityCollection();
|
||||
}
|
||||
|
||||
public string ClassName { get; set; }
|
||||
public string DatabaseName { get; set; }
|
||||
|
||||
public EntityCollection Entities { get; set; }
|
||||
|
||||
public void RenameEntity(string originalName, string newName)
|
||||
{
|
||||
if (originalName == newName)
|
||||
return;
|
||||
|
||||
Debug.WriteLine("Rename Entity '{0}' to '{1}'.", originalName, newName);
|
||||
foreach (var entity in Entities)
|
||||
{
|
||||
if (entity.ClassName == originalName)
|
||||
entity.ClassName = newName;
|
||||
|
||||
foreach (var relationship in entity.Relationships)
|
||||
{
|
||||
if (relationship.ThisEntity == originalName)
|
||||
relationship.ThisEntity = newName;
|
||||
if (relationship.OtherEntity == originalName)
|
||||
relationship.OtherEntity = newName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenameProperty(string entityName, string originalName, string newName)
|
||||
{
|
||||
if (originalName == newName)
|
||||
return;
|
||||
|
||||
Debug.WriteLine("Rename Property '{0}' to '{1}' in Entity '{2}'.", originalName, newName, entityName);
|
||||
foreach (var entity in Entities)
|
||||
{
|
||||
if (entity.ClassName == entityName)
|
||||
{
|
||||
var property = entity.Properties.ByProperty(originalName);
|
||||
if (property != null)
|
||||
property.PropertyName = newName;
|
||||
}
|
||||
|
||||
foreach (var relationship in entity.Relationships)
|
||||
{
|
||||
if (relationship.ThisEntity == entityName)
|
||||
for (int i = 0; i < relationship.ThisProperties.Count; i++)
|
||||
if (relationship.ThisProperties[i] == originalName)
|
||||
relationship.ThisProperties[i] = newName;
|
||||
|
||||
if (relationship.OtherEntity == entityName)
|
||||
for (int i = 0; i < relationship.OtherProperties.Count; i++)
|
||||
if (relationship.OtherProperties[i] == originalName)
|
||||
relationship.OtherProperties[i] = newName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Class: {ClassName}, Table: {FullName}, Context: {ContextName}")]
|
||||
public class Entity : EntityBase
|
||||
{
|
||||
public Entity()
|
||||
{
|
||||
Properties = new PropertyCollection();
|
||||
Relationships = new RelationshipCollection();
|
||||
Methods = new MethodCollection();
|
||||
}
|
||||
|
||||
public string ContextName { get; set; }
|
||||
public string ClassName { get; set; }
|
||||
public string MappingName { get; set; }
|
||||
public string Description{ get;set;}
|
||||
|
||||
public string TableSchema { get; set; }
|
||||
public string TableName { get; set; }
|
||||
public string FullName { get; set; }
|
||||
|
||||
public PropertyCollection Properties { get; set; }
|
||||
public RelationshipCollection Relationships { get; set; }
|
||||
public MethodCollection Methods { get; set; }
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Property: {PropertyName}, Column: {ColumnName}, Type: {NativeType}")]
|
||||
public class Property : EntityBase
|
||||
{
|
||||
public string PropertyName { get; set; }
|
||||
public string ColumnName { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
||||
public DbType DataType { get; set; }
|
||||
public string NativeType { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Type SystemType { get; set; }
|
||||
|
||||
public int? Order { get; set; }
|
||||
public bool OrderSpecified
|
||||
{
|
||||
get { return Order.HasValue; }
|
||||
}
|
||||
|
||||
public bool? IsNullable { get; set; }
|
||||
public bool IsNullableSpecified
|
||||
{
|
||||
get { return IsNullable.HasValue; }
|
||||
}
|
||||
|
||||
public bool IsRequired
|
||||
{
|
||||
get { return IsNullable == false; }
|
||||
set { IsNullable = !value; }
|
||||
}
|
||||
public bool IsOptional
|
||||
{
|
||||
get { return IsNullable == true; }
|
||||
set { IsNullable = value; }
|
||||
}
|
||||
|
||||
public bool? IsPrimaryKey { get; set; }
|
||||
public bool IsPrimaryKeySpecified
|
||||
{
|
||||
get { return IsPrimaryKey.HasValue; }
|
||||
}
|
||||
public bool? IsForeignKey { get; set; }
|
||||
public bool IsForeignKeySpecified
|
||||
{
|
||||
get { return IsForeignKey.HasValue; }
|
||||
}
|
||||
|
||||
public bool? IsAutoGenerated { get; set; }
|
||||
public bool IsAutoGeneratedSpecified
|
||||
{
|
||||
get { return IsAutoGenerated.HasValue; }
|
||||
}
|
||||
public bool? IsReadOnly { get; set; }
|
||||
public bool IsReadOnlySpecified
|
||||
{
|
||||
get { return IsReadOnly.HasValue; }
|
||||
}
|
||||
public bool? IsRowVersion { get; set; }
|
||||
public bool IsRowVersionSpecified
|
||||
{
|
||||
get { return IsRowVersion.HasValue; }
|
||||
}
|
||||
public bool? IsIdentity { get; set; }
|
||||
public bool IsIdentitySpecified
|
||||
{
|
||||
get { return IsIdentity.HasValue; }
|
||||
}
|
||||
public bool? IsUnique { get; set; }
|
||||
public bool IsUniqueSpecified
|
||||
{
|
||||
get { return IsUnique.HasValue; }
|
||||
}
|
||||
|
||||
public bool? IsUnicode { get; set; }
|
||||
public bool IsUnicodeSpecified
|
||||
{
|
||||
get { return IsUnicode.HasValue; }
|
||||
}
|
||||
public bool? IsFixedLength { get; set; }
|
||||
public bool IsFixedLengthSpecified
|
||||
{
|
||||
get { return IsFixedLength.HasValue; }
|
||||
}
|
||||
|
||||
public int? MaxLength { get; set; }
|
||||
public bool MaxLengthSpecified
|
||||
{
|
||||
get { return MaxLength.HasValue; }
|
||||
}
|
||||
|
||||
public byte? Precision { get; set; }
|
||||
public bool PrecisionSpecified
|
||||
{
|
||||
get { return Precision.HasValue; }
|
||||
}
|
||||
public int? Scale { get; set; }
|
||||
public bool ScaleSpecified
|
||||
{
|
||||
get { return Scale.HasValue; }
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Other: {OtherEntity}, Property: {OtherPropertyName}, Relationship: {RelationshipName}")]
|
||||
public class Relationship : EntityBase
|
||||
{
|
||||
public Relationship()
|
||||
{
|
||||
OtherProperties = new List<string>();
|
||||
ThisProperties = new List<string>();
|
||||
}
|
||||
|
||||
public string RelationshipName { get; set; }
|
||||
|
||||
public string ThisEntity { get; set; }
|
||||
public string ThisPropertyName { get; set; }
|
||||
public Cardinality ThisCardinality { get; set; }
|
||||
public List<string> ThisProperties { get; set; }
|
||||
|
||||
public string OtherEntity { get; set; }
|
||||
public string OtherPropertyName { get; set; }
|
||||
public Cardinality OtherCardinality { get; set; }
|
||||
public List<string> OtherProperties { get; set; }
|
||||
|
||||
public bool? CascadeDelete { get; set; }
|
||||
public bool IsForeignKey { get; set; }
|
||||
public bool IsMapped { get; set; }
|
||||
|
||||
public bool IsManyToMany
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisCardinality == Cardinality.Many
|
||||
&& OtherCardinality == Cardinality.Many;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOneToOne
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisCardinality != Cardinality.Many
|
||||
&& OtherCardinality != Cardinality.Many;
|
||||
}
|
||||
}
|
||||
|
||||
public string JoinTable { get; set; }
|
||||
public string JoinSchema { get; set; }
|
||||
public List<string> JoinThisColumn { get; set; }
|
||||
public List<string> JoinOtherColumn { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Suffix: {NameSuffix}, IsKey: {IsKey}, IsUnique: {IsUnique}")]
|
||||
public class Method : EntityBase
|
||||
{
|
||||
public Method()
|
||||
{
|
||||
Properties = new List<Property>();
|
||||
}
|
||||
|
||||
public string NameSuffix { get; set; }
|
||||
public string SourceName { get; set; }
|
||||
|
||||
public bool IsKey { get; set; }
|
||||
public bool IsUnique { get; set; }
|
||||
public bool IsIndex { get; set; }
|
||||
|
||||
public List<Property> Properties { get; set; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Collections
|
||||
public class EntityCollection
|
||||
: ObservableCollection<Entity>
|
||||
{
|
||||
public bool IsProcessed { get; set; }
|
||||
|
||||
public Entity ByTable(string fullName)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.FullName == fullName);
|
||||
}
|
||||
|
||||
public Entity ByTable(string tableName, string tableSchema)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.TableName == tableName && x.TableSchema == tableSchema);
|
||||
}
|
||||
|
||||
public Entity ByClass(string className)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.ClassName == className);
|
||||
}
|
||||
|
||||
public Entity ByContext(string contextName)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.ContextName == contextName);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropertyCollection
|
||||
: ObservableCollection<Property>
|
||||
{
|
||||
public bool IsProcessed { get; set; }
|
||||
|
||||
public IEnumerable<Property> PrimaryKeys
|
||||
{
|
||||
get { return this.Where(p => p.IsPrimaryKey == true); }
|
||||
}
|
||||
|
||||
public IEnumerable<Property> ForeignKeys
|
||||
{
|
||||
get { return this.Where(p => p.IsForeignKey == true); }
|
||||
}
|
||||
|
||||
public Property ByColumn(string columnName)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.ColumnName == columnName);
|
||||
}
|
||||
|
||||
public Property ByProperty(string propertyName)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.PropertyName == propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public class RelationshipCollection
|
||||
: ObservableCollection<Relationship>
|
||||
{
|
||||
public bool IsProcessed { get; set; }
|
||||
|
||||
public Relationship ByName(string name)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.RelationshipName == name);
|
||||
}
|
||||
|
||||
public Relationship ByProperty(string propertyName)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.ThisPropertyName == propertyName);
|
||||
}
|
||||
|
||||
public Relationship ByOther(string name)
|
||||
{
|
||||
return this.FirstOrDefault(x => x.OtherEntity == name);
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodCollection
|
||||
: ObservableCollection<Method>
|
||||
{
|
||||
public bool IsProcessed { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,639 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ICSharpCode.NRefactory.CSharp;
|
||||
|
||||
namespace SchemaMapper
|
||||
{
|
||||
#region Mapping Parser
|
||||
[DebuggerDisplay("Table: {TableName}, Entity: {EntityClass}, Mapping: {MappingClass}")]
|
||||
public class ParsedEntity
|
||||
{
|
||||
public ParsedEntity()
|
||||
{
|
||||
Properties = new List<ParsedProperty>();
|
||||
Relationships = new List<ParsedRelationship>();
|
||||
}
|
||||
|
||||
public string EntityClass { get; set; }
|
||||
public string MappingClass { get; set; }
|
||||
|
||||
public string TableName { get; set; }
|
||||
public string TableSchema { get; set; }
|
||||
|
||||
public List<ParsedProperty> Properties { get; private set; }
|
||||
public List<ParsedRelationship> Relationships { get; private set; }
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Column: {ColumnName}, Property: {PropertyName}")]
|
||||
public class ParsedProperty
|
||||
{
|
||||
public string ColumnName { get; set; }
|
||||
public string PropertyName { get; set; }
|
||||
}
|
||||
|
||||
[DebuggerDisplay("This: {ThisPropertyName}, Other: {OtherPropertyName}")]
|
||||
public class ParsedRelationship
|
||||
{
|
||||
public ParsedRelationship()
|
||||
{
|
||||
ThisProperties = new List<string>();
|
||||
JoinThisColumn = new List<string>();
|
||||
JoinOtherColumn = new List<string>();
|
||||
}
|
||||
|
||||
public string ThisPropertyName { get; set; }
|
||||
public List<string> ThisProperties { get; private set; }
|
||||
|
||||
public string OtherPropertyName { get; set; }
|
||||
|
||||
public string JoinTable { get; set; }
|
||||
public string JoinSchema { get; set; }
|
||||
public List<string> JoinThisColumn { get; private set; }
|
||||
public List<string> JoinOtherColumn { get; private set; }
|
||||
}
|
||||
|
||||
public class MappingVisitor : DepthFirstAstVisitor<object, object>
|
||||
{
|
||||
public MappingVisitor()
|
||||
{
|
||||
MappingBaseType = "EntityTypeConfiguration";
|
||||
}
|
||||
|
||||
public string MappingBaseType { get; set; }
|
||||
public ParsedEntity ParsedEntity { get; set; }
|
||||
|
||||
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
|
||||
{
|
||||
var baseType = typeDeclaration.BaseTypes.OfType<MemberType>().FirstOrDefault();
|
||||
if (baseType == null || baseType.MemberName != MappingBaseType)
|
||||
return base.VisitTypeDeclaration(typeDeclaration, data);
|
||||
|
||||
var entity = baseType.TypeArguments.OfType<MemberType>().FirstOrDefault();
|
||||
if (entity == null)
|
||||
return base.VisitTypeDeclaration(typeDeclaration, data);
|
||||
|
||||
if (ParsedEntity == null)
|
||||
ParsedEntity = new ParsedEntity();
|
||||
|
||||
ParsedEntity.EntityClass = entity.MemberName;
|
||||
ParsedEntity.MappingClass = typeDeclaration.Name;
|
||||
|
||||
return base.VisitTypeDeclaration(typeDeclaration, ParsedEntity);
|
||||
}
|
||||
|
||||
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
|
||||
{
|
||||
if (data == null)
|
||||
return base.VisitInvocationExpression(invocationExpression, null);
|
||||
|
||||
// visit all the methods
|
||||
var identifier = invocationExpression.Target.Children.OfType<Identifier>().FirstOrDefault();
|
||||
string methodName = identifier == null ? string.Empty : identifier.Name;
|
||||
|
||||
// the different types of incoming data, helps us know what we're parsing
|
||||
var parsedEntity = data as ParsedEntity;
|
||||
var parsedProperty = data as ParsedProperty;
|
||||
var parsedRelationship = data as ParsedRelationship;
|
||||
|
||||
switch (methodName)
|
||||
{
|
||||
case "ToTable":
|
||||
var tableNameExpression = invocationExpression.Arguments
|
||||
.OfType<PrimitiveExpression>()
|
||||
.ToArray();
|
||||
|
||||
string tableName = null;
|
||||
string tableSchema = null;
|
||||
|
||||
if (tableNameExpression.Length >= 1)
|
||||
tableName = tableNameExpression[0].Value.ToString();
|
||||
if (tableNameExpression.Length >= 2)
|
||||
tableSchema = tableNameExpression[1].Value.ToString();
|
||||
|
||||
// ToTable is either Entity -> Table map or Many to Many map
|
||||
if (parsedEntity != null)
|
||||
{
|
||||
// when data is ParsedEntity, entity map
|
||||
parsedEntity.TableName = tableName;
|
||||
parsedEntity.TableSchema = tableSchema;
|
||||
}
|
||||
else if (parsedRelationship != null)
|
||||
{
|
||||
// when data is ParsedRelationship, many to many map
|
||||
parsedRelationship.JoinTable = tableName;
|
||||
parsedRelationship.JoinSchema = tableSchema;
|
||||
}
|
||||
break;
|
||||
case "HasColumnName":
|
||||
var columnNameExpression = invocationExpression.Arguments
|
||||
.OfType<PrimitiveExpression>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (columnNameExpression == null)
|
||||
break;
|
||||
|
||||
// property to column map start.
|
||||
string columnName = columnNameExpression.Value.ToString();
|
||||
var property = new ParsedProperty { ColumnName = columnName };
|
||||
ParsedEntity.Properties.Add(property);
|
||||
|
||||
//only have column info at this point. pass data to get property name.
|
||||
return base.VisitInvocationExpression(invocationExpression, property);
|
||||
case "Property":
|
||||
var propertyExpression = invocationExpression.Arguments
|
||||
.OfType<LambdaExpression>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (parsedProperty == null || propertyExpression == null)
|
||||
break;
|
||||
|
||||
// ParsedProperty is passed in as data from HasColumnName, add property name
|
||||
var propertyBodyExpression = propertyExpression.Body as MemberReferenceExpression;
|
||||
if (propertyBodyExpression != null)
|
||||
parsedProperty.PropertyName = propertyBodyExpression.MemberName;
|
||||
|
||||
break;
|
||||
case "Map":
|
||||
// start a new Many to Many relationship
|
||||
var mapRelation = new ParsedRelationship();
|
||||
ParsedEntity.Relationships.Add(mapRelation);
|
||||
// pass to child nodes to fill in data
|
||||
return base.VisitInvocationExpression(invocationExpression, mapRelation);
|
||||
case "HasForeignKey":
|
||||
var foreignExpression = invocationExpression.Arguments
|
||||
.OfType<LambdaExpression>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (foreignExpression == null)
|
||||
break;
|
||||
|
||||
// when only 1 fkey, body will be member ref
|
||||
if (foreignExpression.Body is MemberReferenceExpression)
|
||||
{
|
||||
var foreignBodyExpression = foreignExpression.Body as MemberReferenceExpression;
|
||||
// start a new relationship
|
||||
var foreignRelation = new ParsedRelationship();
|
||||
ParsedEntity.Relationships.Add(foreignRelation);
|
||||
|
||||
foreignRelation.ThisProperties.Add(foreignBodyExpression.MemberName);
|
||||
// pass as data for child nodes to fill in data
|
||||
return base.VisitInvocationExpression(invocationExpression, foreignRelation);
|
||||
}
|
||||
// when more then 1 fkey, body will be an anonymous type
|
||||
if (foreignExpression.Body is AnonymousTypeCreateExpression)
|
||||
{
|
||||
var foreignBodyExpression = foreignExpression.Body as AnonymousTypeCreateExpression;
|
||||
var foreignRelation = new ParsedRelationship();
|
||||
ParsedEntity.Relationships.Add(foreignRelation);
|
||||
|
||||
var properties = foreignBodyExpression.Children
|
||||
.OfType<MemberReferenceExpression>()
|
||||
.Select(m => m.MemberName);
|
||||
|
||||
foreignRelation.ThisProperties.AddRange(properties);
|
||||
|
||||
return base.VisitInvocationExpression(invocationExpression, foreignRelation);
|
||||
}
|
||||
break;
|
||||
case "HasMany":
|
||||
var hasManyExpression = invocationExpression.Arguments
|
||||
.OfType<LambdaExpression>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (parsedRelationship == null || hasManyExpression == null)
|
||||
break;
|
||||
|
||||
// filling existing relationship data
|
||||
var hasManyBodyExpression = hasManyExpression.Body as MemberReferenceExpression;
|
||||
if (hasManyBodyExpression != null)
|
||||
parsedRelationship.ThisPropertyName = hasManyBodyExpression.MemberName;
|
||||
|
||||
break;
|
||||
case "WithMany":
|
||||
var withManyExpression = invocationExpression.Arguments
|
||||
.OfType<LambdaExpression>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (parsedRelationship == null || withManyExpression == null)
|
||||
break;
|
||||
|
||||
// filling existing relationship data
|
||||
var withManyBodyExpression = withManyExpression.Body as MemberReferenceExpression;
|
||||
if (withManyBodyExpression != null)
|
||||
parsedRelationship.OtherPropertyName = withManyBodyExpression.MemberName;
|
||||
|
||||
break;
|
||||
case "HasRequired":
|
||||
case "HasOptional":
|
||||
var hasExpression = invocationExpression.Arguments
|
||||
.OfType<LambdaExpression>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (parsedRelationship == null || hasExpression == null)
|
||||
break;
|
||||
|
||||
// filling existing relationship data
|
||||
var hasBodyExpression = hasExpression.Body as MemberReferenceExpression;
|
||||
if (hasBodyExpression != null)
|
||||
parsedRelationship.ThisPropertyName = hasBodyExpression.MemberName;
|
||||
|
||||
break;
|
||||
case "MapLeftKey":
|
||||
if (parsedRelationship == null)
|
||||
break;
|
||||
|
||||
var leftKeyExpression = invocationExpression.Arguments
|
||||
.OfType<PrimitiveExpression>()
|
||||
.Select(e => e.Value.ToString());
|
||||
|
||||
parsedRelationship.JoinThisColumn.AddRange(leftKeyExpression);
|
||||
break;
|
||||
case "MapRightKey":
|
||||
if (parsedRelationship == null)
|
||||
break;
|
||||
|
||||
var rightKeyExpression = invocationExpression.Arguments
|
||||
.OfType<PrimitiveExpression>()
|
||||
.Select(e => e.Value.ToString());
|
||||
|
||||
parsedRelationship.JoinOtherColumn.AddRange(rightKeyExpression);
|
||||
break;
|
||||
}
|
||||
|
||||
return base.VisitInvocationExpression(invocationExpression, data);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MappingParser
|
||||
{
|
||||
public static ParsedEntity Parse(string mappingFile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(mappingFile) || !File.Exists(mappingFile))
|
||||
return null;
|
||||
|
||||
var parser = new CSharpParser();
|
||||
CompilationUnit compilationUnit;
|
||||
|
||||
using (var stream = File.OpenText(mappingFile))
|
||||
compilationUnit = parser.Parse(stream, mappingFile);
|
||||
|
||||
var visitor = new MappingVisitor();
|
||||
|
||||
visitor.VisitCompilationUnit(compilationUnit, null);
|
||||
var parsedEntity = visitor.ParsedEntity;
|
||||
|
||||
if (parsedEntity != null)
|
||||
Debug.WriteLine("Parsed Mapping File: '{0}'; Properties: {1}; Relationships: {2}",
|
||||
Path.GetFileName(mappingFile),
|
||||
parsedEntity.Properties.Count,
|
||||
parsedEntity.Relationships.Count);
|
||||
|
||||
return parsedEntity;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Context Parser
|
||||
[DebuggerDisplay("Context: {ContextClass}")]
|
||||
public class ParsedContext
|
||||
{
|
||||
public ParsedContext()
|
||||
{
|
||||
Properties = new List<ParsedEntitySet>();
|
||||
}
|
||||
|
||||
public string ContextClass { get; set; }
|
||||
|
||||
public List<ParsedEntitySet> Properties { get; private set; }
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Entity: {EntityClass}, Property: {ContextProperty}")]
|
||||
public class ParsedEntitySet
|
||||
{
|
||||
public string EntityClass { get; set; }
|
||||
public string ContextProperty { get; set; }
|
||||
}
|
||||
|
||||
public class ContextVisitor : DepthFirstAstVisitor<object, object>
|
||||
{
|
||||
public ContextVisitor()
|
||||
{
|
||||
ContextBaseType = "DbContext";
|
||||
DataSetType = "DbSet";
|
||||
}
|
||||
|
||||
public string ContextBaseType { get; set; }
|
||||
public string DataSetType { get; set; }
|
||||
|
||||
public ParsedContext ParsedContext { get; set; }
|
||||
|
||||
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
|
||||
{
|
||||
var baseType = typeDeclaration.BaseTypes
|
||||
.OfType<MemberType>()
|
||||
.FirstOrDefault();
|
||||
|
||||
// warning: if inherited from custom base type, this will break
|
||||
// anyway to improve this?
|
||||
if (baseType == null || baseType.MemberName != ContextBaseType)
|
||||
return base.VisitTypeDeclaration(typeDeclaration, data);
|
||||
|
||||
if (ParsedContext == null)
|
||||
ParsedContext = new ParsedContext();
|
||||
|
||||
ParsedContext.ContextClass = typeDeclaration.Name;
|
||||
|
||||
return base.VisitTypeDeclaration(typeDeclaration, ParsedContext);
|
||||
}
|
||||
|
||||
public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
|
||||
{
|
||||
if (data == null)
|
||||
return base.VisitPropertyDeclaration(propertyDeclaration, null);
|
||||
|
||||
// look for property to return generic DbSet type
|
||||
var memberType = propertyDeclaration.ReturnType as MemberType;
|
||||
if (memberType == null || memberType.MemberName != DataSetType)
|
||||
return base.VisitPropertyDeclaration(propertyDeclaration, data);
|
||||
|
||||
// get the first generic type
|
||||
var entityType = memberType.TypeArguments
|
||||
.OfType<MemberType>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (entityType == null)
|
||||
return base.VisitPropertyDeclaration(propertyDeclaration, data);
|
||||
|
||||
var entitySet = new ParsedEntitySet
|
||||
{
|
||||
EntityClass = entityType.MemberName,
|
||||
ContextProperty = propertyDeclaration.Name
|
||||
};
|
||||
|
||||
ParsedContext.Properties.Add(entitySet);
|
||||
|
||||
return base.VisitPropertyDeclaration(propertyDeclaration, data);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ContextParser
|
||||
{
|
||||
public static ParsedContext Parse(string contextFile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(contextFile) || !File.Exists(contextFile))
|
||||
return null;
|
||||
|
||||
var parser = new CSharpParser();
|
||||
CompilationUnit compilationUnit;
|
||||
|
||||
using (var stream = File.OpenText(contextFile))
|
||||
compilationUnit = parser.Parse(stream, contextFile);
|
||||
|
||||
var visitor = new ContextVisitor();
|
||||
|
||||
visitor.VisitCompilationUnit(compilationUnit, null);
|
||||
var parsedContext = visitor.ParsedContext;
|
||||
|
||||
if (parsedContext != null)
|
||||
Debug.WriteLine("Parsed Context File: '{0}'; Entities: {1}",
|
||||
Path.GetFileName(contextFile),
|
||||
parsedContext.Properties.Count);
|
||||
|
||||
return parsedContext;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static class Synchronizer
|
||||
{
|
||||
public static bool UpdateFromSource(EntityContext generatedContext, string contextDirectory, string mappingDirectory)
|
||||
{
|
||||
if (generatedContext == null)
|
||||
return false;
|
||||
|
||||
// make sure to update the entities before the context
|
||||
UpdateFromMapping(generatedContext, mappingDirectory);
|
||||
UpdateFromContext(generatedContext, contextDirectory);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void UpdateFromContext(EntityContext generatedContext, string contextDirectory)
|
||||
{
|
||||
if (generatedContext == null
|
||||
|| contextDirectory == null
|
||||
|| !Directory.Exists(contextDirectory))
|
||||
return;
|
||||
|
||||
// parse context
|
||||
ParsedContext parsedContext = null;
|
||||
var files = Directory.EnumerateFiles(contextDirectory, "*.Generated.cs").GetEnumerator();
|
||||
while (files.MoveNext() && parsedContext == null)
|
||||
parsedContext = ContextParser.Parse(files.Current);
|
||||
|
||||
if (parsedContext == null)
|
||||
return;
|
||||
|
||||
if (generatedContext.ClassName != parsedContext.ContextClass)
|
||||
{
|
||||
Debug.WriteLine("Rename Context Class'{0}' to '{1}'.",
|
||||
generatedContext.ClassName,
|
||||
parsedContext.ContextClass);
|
||||
|
||||
generatedContext.ClassName = parsedContext.ContextClass;
|
||||
}
|
||||
|
||||
foreach (var parsedProperty in parsedContext.Properties)
|
||||
{
|
||||
var entity = generatedContext.Entities.ByClass(parsedProperty.EntityClass);
|
||||
if (entity == null)
|
||||
continue;
|
||||
|
||||
|
||||
if (entity.ContextName == parsedProperty.ContextProperty)
|
||||
continue;
|
||||
|
||||
Debug.WriteLine("Rename Context Property'{0}' to '{1}'.",
|
||||
entity.ContextName,
|
||||
parsedProperty.ContextProperty);
|
||||
|
||||
entity.ContextName = parsedProperty.ContextProperty;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateFromMapping(EntityContext generatedContext, string mappingDirectory)
|
||||
{
|
||||
if (generatedContext == null
|
||||
|| mappingDirectory == null
|
||||
|| !Directory.Exists(mappingDirectory))
|
||||
return;
|
||||
|
||||
// parse all mapping files
|
||||
var mappingFiles = Directory.EnumerateFiles(mappingDirectory, "*.Generated.cs");
|
||||
var parsedEntities = mappingFiles
|
||||
.Select(MappingParser.Parse)
|
||||
.Where(parsedEntity => parsedEntity != null)
|
||||
.ToList();
|
||||
|
||||
var relationshipQueue = new List<Tuple<Entity, ParsedEntity>>();
|
||||
|
||||
// update all entity and property names first because relationships are linked by property names
|
||||
foreach (var parsedEntity in parsedEntities)
|
||||
{
|
||||
// find entity by table name to support renaming entity
|
||||
var entity = generatedContext.Entities
|
||||
.ByTable(parsedEntity.TableName, parsedEntity.TableSchema);
|
||||
|
||||
if (entity == null)
|
||||
continue;
|
||||
|
||||
// sync names
|
||||
if (entity.MappingName != parsedEntity.MappingClass)
|
||||
{
|
||||
Debug.WriteLine("Rename Mapping Class'{0}' to '{1}'.",
|
||||
entity.MappingName,
|
||||
parsedEntity.MappingClass);
|
||||
|
||||
entity.MappingName = parsedEntity.MappingClass;
|
||||
}
|
||||
|
||||
// use rename api to make sure all instances are renamed
|
||||
generatedContext.RenameEntity(entity.ClassName, parsedEntity.EntityClass);
|
||||
|
||||
// sync properties
|
||||
foreach (var parsedProperty in parsedEntity.Properties)
|
||||
{
|
||||
// find property by column name to support property name rename
|
||||
var property = entity.Properties.ByColumn(parsedProperty.ColumnName);
|
||||
if (property == null)
|
||||
continue;
|
||||
|
||||
// use rename api to make sure all instances are renamed
|
||||
generatedContext.RenameProperty(
|
||||
entity.ClassName,
|
||||
property.PropertyName,
|
||||
parsedProperty.PropertyName);
|
||||
}
|
||||
|
||||
// save relationship for later processing
|
||||
var item = new Tuple<Entity, ParsedEntity>(entity, parsedEntity);
|
||||
relationshipQueue.Add(item);
|
||||
}
|
||||
|
||||
// update relationships last
|
||||
foreach (var tuple in relationshipQueue)
|
||||
UpdateRelationships(generatedContext, tuple.Item1, tuple.Item2);
|
||||
}
|
||||
|
||||
private static void UpdateRelationships(EntityContext generatedContext, Entity entity, ParsedEntity parsedEntity)
|
||||
{
|
||||
// sync relationships
|
||||
foreach (var parsedRelationship in parsedEntity.Relationships.Where(r => r.JoinTable == null))
|
||||
{
|
||||
var parsedProperties = parsedRelationship.ThisProperties;
|
||||
var relationship = entity.Relationships
|
||||
.Where(r => !r.IsManyToMany)
|
||||
.FirstOrDefault(r => r.ThisProperties.Except(parsedProperties).Count() == 0);
|
||||
|
||||
if (relationship == null)
|
||||
continue;
|
||||
|
||||
bool isThisSame = relationship.ThisPropertyName == parsedRelationship.ThisPropertyName;
|
||||
bool isOtherSame = relationship.OtherPropertyName == parsedRelationship.OtherPropertyName;
|
||||
|
||||
if (isThisSame && isOtherSame)
|
||||
continue;
|
||||
|
||||
if (!isThisSame)
|
||||
{
|
||||
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
|
||||
relationship.ThisEntity,
|
||||
relationship.ThisPropertyName,
|
||||
parsedRelationship.ThisPropertyName);
|
||||
|
||||
relationship.ThisPropertyName = parsedRelationship.ThisPropertyName;
|
||||
}
|
||||
if (!isOtherSame)
|
||||
{
|
||||
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
|
||||
relationship.OtherEntity,
|
||||
relationship.OtherPropertyName,
|
||||
parsedRelationship.OtherPropertyName);
|
||||
|
||||
relationship.OtherPropertyName = parsedRelationship.OtherPropertyName;
|
||||
}
|
||||
|
||||
// sync other relationship
|
||||
var otherEntity = generatedContext.Entities.ByClass(relationship.OtherEntity);
|
||||
if (otherEntity == null)
|
||||
continue;
|
||||
|
||||
var otherRelationship = otherEntity.Relationships.ByName(relationship.RelationshipName);
|
||||
if (otherRelationship == null)
|
||||
continue;
|
||||
|
||||
otherRelationship.ThisPropertyName = relationship.OtherPropertyName;
|
||||
otherRelationship.OtherPropertyName = relationship.ThisPropertyName;
|
||||
}
|
||||
|
||||
// sync many to many
|
||||
foreach (var parsedRelationship in parsedEntity.Relationships.Where(r => r.JoinTable != null))
|
||||
{
|
||||
var joinThisColumn = parsedRelationship.JoinThisColumn;
|
||||
var joinOtherColumn = parsedRelationship.JoinOtherColumn;
|
||||
|
||||
var relationship = entity.Relationships
|
||||
.Where(r => r.IsManyToMany)
|
||||
.FirstOrDefault(r =>
|
||||
r.JoinThisColumn.Except(joinThisColumn).Count() == 0 &&
|
||||
r.JoinOtherColumn.Except(joinOtherColumn).Count() == 0 &&
|
||||
r.JoinTable == parsedRelationship.JoinTable &&
|
||||
r.JoinSchema == parsedRelationship.JoinSchema);
|
||||
|
||||
if (relationship == null)
|
||||
continue;
|
||||
|
||||
|
||||
bool isThisSame = relationship.ThisPropertyName == parsedRelationship.ThisPropertyName;
|
||||
bool isOtherSame = relationship.OtherPropertyName == parsedRelationship.OtherPropertyName;
|
||||
|
||||
if (isThisSame && isOtherSame)
|
||||
continue;
|
||||
|
||||
if (!isThisSame)
|
||||
{
|
||||
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
|
||||
relationship.ThisEntity,
|
||||
relationship.ThisPropertyName,
|
||||
parsedRelationship.ThisPropertyName);
|
||||
|
||||
relationship.ThisPropertyName = parsedRelationship.ThisPropertyName;
|
||||
}
|
||||
if (!isOtherSame)
|
||||
{
|
||||
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
|
||||
relationship.OtherEntity,
|
||||
relationship.OtherPropertyName,
|
||||
parsedRelationship.OtherPropertyName);
|
||||
|
||||
relationship.OtherPropertyName = parsedRelationship.OtherPropertyName;
|
||||
}
|
||||
|
||||
// sync other relationship
|
||||
var otherEntity = generatedContext.Entities.ByClass(relationship.OtherEntity);
|
||||
if (otherEntity == null)
|
||||
continue;
|
||||
|
||||
var otherRelationship = otherEntity.Relationships.ByName(relationship.RelationshipName);
|
||||
if (otherRelationship == null)
|
||||
continue;
|
||||
|
||||
otherRelationship.ThisPropertyName = relationship.OtherPropertyName;
|
||||
otherRelationship.OtherPropertyName = relationship.ThisPropertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<%--
|
||||
Name: Database Table Properties
|
||||
Author: yubaolee
|
||||
Description: Create a list of properties from a database table
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="False" Description="控制器" %>
|
||||
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenAuth.App;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.Repository.Domain;
|
||||
|
||||
namespace OpenAuth.Mvc.Controllers
|
||||
{
|
||||
public class <%=ModuleName%>sController : BaseController
|
||||
{
|
||||
private readonly <%=ModuleName%>App _app;
|
||||
|
||||
public <%=ModuleName%>sController(<%=ModuleName%>App app, IAuth auth) : base(auth)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
|
||||
//主页
|
||||
public ActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MVC界面添加
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public string Add(AddOrUpdate<%=ModuleName%>Req obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
_app.Add(obj);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Result.Code = 500;
|
||||
Result.Message = ex.Message;
|
||||
}
|
||||
return JsonHelper.Instance.Serialize(Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MVC界面修改
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public string Update(AddOrUpdate<%=ModuleName%>Req obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
_app.Update(obj);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Result.Code = 500;
|
||||
Result.Message = ex.Message;
|
||||
}
|
||||
return JsonHelper.Instance.Serialize(Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载列表
|
||||
/// </summary>
|
||||
public string Load([FromQuery]Query<%=ModuleName%>ListReq request)
|
||||
{
|
||||
return JsonHelper.Instance.Serialize(_app.Load(request));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public string Delete(string[] ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
_app.Delete(ids);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Result.Code = 500;
|
||||
Result.Message = e.Message;
|
||||
}
|
||||
|
||||
return JsonHelper.Instance.Serialize(Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<%--
|
||||
Name: 列表页面
|
||||
Author: yubaolee
|
||||
Description: 列表页面
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Encoding="utf-8" Description="添加模块" %>
|
||||
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context"
|
||||
Description="连接的数据库" %>
|
||||
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
|
||||
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
<%@ Assembly Src="Util.cs" %>
|
||||
<%@ Import Namespace="Util" %>
|
||||
|
||||
@section header
|
||||
{
|
||||
<link rel="stylesheet" href="/css/treetable.css" />
|
||||
}
|
||||
<blockquote class="layui-elem-quote news_search toolList" id="menus">
|
||||
</blockquote>
|
||||
|
||||
<div class="layui-card">
|
||||
|
||||
<table class="layui-table" id="mainList"
|
||||
lay-data="{height: 'full-80', page:true, id:'mainList'}"
|
||||
lay-filter="list" lay-size="sm">
|
||||
</table>
|
||||
|
||||
<script type="text/html" id="Disable">
|
||||
{{# if(d.Disable){ }}
|
||||
<span class="layui-badge">已禁用</span>
|
||||
{{# } else{}}
|
||||
<span class="layui-badge layui-bg-green">正常</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
<!--添加/编辑窗口-->
|
||||
<div id="divEdit" style="display: none">
|
||||
<form class="layui-form" action="" id="formEdit">
|
||||
<% foreach (ColumnSchema column in this.SourceTable.Columns) {
|
||||
if(column.IsPrimaryKeyMember){%>
|
||||
<input type="hidden" name="<%=column.Name%>" v-model="tmp.<%=column.Name%>" />
|
||||
<%}else if(CSharpAlias[column.SystemType.FullName] == "bool") {%>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="<%=column.Name%>" v-model="tmp.<%=column.Name%>" lay-skin="switch" value="1">
|
||||
</div>
|
||||
</div>
|
||||
<%}else if(CSharpAlias[column.SystemType.FullName] == "int" ) {%>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="<%=column.Name%>" value="1" title="value1" checked>
|
||||
<input type="radio" name="<%=column.Name%>" value="0" title="value2">
|
||||
</div>
|
||||
</div>
|
||||
<%} else {%>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="<%=column.Name%>" v-model="tmp.<%=column.Name%>" required lay-verify="required"
|
||||
placeholder="<%=Tools.GetDescription(column)%>" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<%} %>
|
||||
<%} %>
|
||||
|
||||
<%if(Tools.NeedCascade(SourceTable)){ %>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">所属部门</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="Organizations" name="Organizations" v-model="Organizations" required lay-verify="required" class="layui-input" />
|
||||
<input id="OrganizationIds" name="OrganizationIds" v-model="OrganizationIds" required lay-verify="required" type="hidden" />
|
||||
<div id="menuContent" class="menuContent" style="display: none;">
|
||||
<ul id="org" class="ztree"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%} %>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="formSubmit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="/userJs/<%=ModuleName.ToLower()%>s.js"></script>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CodeSmith.Engine;
|
||||
using SchemaExplorer;
|
||||
|
||||
namespace Util{
|
||||
public class Tools{
|
||||
public static String GetDescription(ColumnSchema column) { //得到字段的描述
|
||||
if(string.IsNullOrEmpty(column.Description))
|
||||
return column.Name;
|
||||
else
|
||||
return column.Description;
|
||||
}
|
||||
|
||||
public static bool NeedCascade(TableSchema SourceTable){ //判断表中是否需要下拉选择树
|
||||
return SourceTable.Columns.Contains("ParentId")
|
||||
|| SourceTable.Columns.Contains("CascadeId") ;
|
||||
}
|
||||
|
||||
|
||||
public static string CreateBlank(int level){
|
||||
if(level == 1){
|
||||
return " ";
|
||||
}
|
||||
else{
|
||||
var twoblanks = " ";
|
||||
for (int i = level-1; i > 1; i--)
|
||||
{
|
||||
twoblanks +=twoblanks;
|
||||
}
|
||||
return CreateBlank(1) + twoblanks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
<%--
|
||||
Name: 主JS界面
|
||||
Author: yubaolee
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Encoding="utf-8" Description="添加模块" %>
|
||||
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
|
||||
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
<%@ Assembly Src="Util.cs" %>
|
||||
<%@ Import Namespace="Util" %>
|
||||
|
||||
layui.config({
|
||||
base: "/js/"
|
||||
}).use(['form', 'vue', 'ztree', 'layer', 'jquery', 'table', 'droptree', 'openauth', 'utils'], function () {
|
||||
var form = layui.form,
|
||||
layer = layui.layer,
|
||||
$ = layui.jquery;
|
||||
var table = layui.table;
|
||||
var openauth = layui.openauth;
|
||||
var toplayer = (top == undefined || top.layer === undefined) ? layer : top.layer; //顶层的LAYER
|
||||
|
||||
$("#menus").loadMenus("<%=ModuleName%>");
|
||||
|
||||
|
||||
//加载表头
|
||||
$.getJSON('/<%=ModuleName%>s/Load',
|
||||
{ page: 1, limit: 1 },
|
||||
function (data) {
|
||||
var columns = data.columnFields.filter(u => u.IsList ===true).map(function (e) {
|
||||
return {
|
||||
field: e.ColumnName,
|
||||
title: e.Comment
|
||||
};
|
||||
});
|
||||
columns.unshift({
|
||||
type: 'checkbox',
|
||||
fixed: 'left'
|
||||
});
|
||||
table.render({
|
||||
elem: '#mainList',
|
||||
page: true,
|
||||
url: '/<%=ModuleName%>s/Load',
|
||||
cols: [columns]
|
||||
, response: {
|
||||
statusCode: 200 //规定成功的状态码,默认:0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//主列表加载,可反复调用进行刷新
|
||||
var config = {}; //table的参数,如搜索key,点击tree的id
|
||||
var mainList = function(options) {
|
||||
if (options != undefined) {
|
||||
$.extend(config, options);
|
||||
}
|
||||
table.reload('mainList',
|
||||
{
|
||||
url: '/<%=ModuleName%>s/Load',
|
||||
where: config
|
||||
, response: {
|
||||
statusCode: 200 //规定成功的状态码,默认:0
|
||||
}
|
||||
});
|
||||
};
|
||||
mainList();
|
||||
|
||||
//添加(编辑)对话框
|
||||
var editDlg = function () {
|
||||
var vm;
|
||||
var update = false; //是否为更新
|
||||
var show = function (data) {
|
||||
var title = update ? "编辑信息" : "添加";
|
||||
layer.open({
|
||||
title: title,
|
||||
area: ["500px", "400px"],
|
||||
type: 1,
|
||||
content: $('#divEdit'),
|
||||
success: function () {
|
||||
if(vm == undefined){
|
||||
vm = new Vue({
|
||||
el: "#formEdit",
|
||||
data(){
|
||||
return {
|
||||
tmp:data //使用一个tmp封装一下,后面可以直接用vm.tmp赋值
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
tmp(val){
|
||||
this.$nextTick(function () {
|
||||
form.render(); //刷新select等
|
||||
layui.droptree("/Applications/GetList", "#AppName", "#AppId", false);
|
||||
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
form.render();
|
||||
layui.droptree("/Applications/GetList", "#AppName", "#AppId", false);
|
||||
|
||||
}
|
||||
});
|
||||
}else{
|
||||
vm.tmp = Object.assign({}, vm.tmp,data)
|
||||
}
|
||||
},
|
||||
end: mainList
|
||||
});
|
||||
var url = "/<%=ModuleName%>s/Add";
|
||||
if (update) {
|
||||
url = "/<%=ModuleName%>s/Update";
|
||||
}
|
||||
//提交数据
|
||||
form.on('submit(formSubmit)',
|
||||
function (data) {
|
||||
$.post(url,
|
||||
data.field,
|
||||
function (data) {
|
||||
layer.msg(data.Message);
|
||||
},
|
||||
"json");
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return {
|
||||
add: function () { //弹出添加
|
||||
update = false;
|
||||
show({
|
||||
Id: ''
|
||||
});
|
||||
},
|
||||
update: function (data) { //弹出编辑框
|
||||
update = true;
|
||||
show(data);
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
//监听表格内部按钮
|
||||
table.on('tool(list)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'detail') { //查看
|
||||
layer.msg('ID:' + data.Id + ' 的查看操作');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//监听页面主按钮操作
|
||||
var active = {
|
||||
btnDel: function () { //批量删除
|
||||
var checkStatus = table.checkStatus('mainList')
|
||||
, data = checkStatus.data;
|
||||
openauth.del("/<%=ModuleName%>s/Delete",
|
||||
data.map(function (e) { return e.Id; }),
|
||||
mainList);
|
||||
}
|
||||
, btnAdd: function () { //添加
|
||||
editDlg.add();
|
||||
}
|
||||
, btnEdit: function () { //编辑
|
||||
var checkStatus = table.checkStatus('mainList')
|
||||
, data = checkStatus.data;
|
||||
if (data.length != 1) {
|
||||
layer.msg("请选择编辑的行,且同时只能编辑一行");
|
||||
return;
|
||||
}
|
||||
editDlg.update(data[0]);
|
||||
}
|
||||
|
||||
, search: function () { //搜索
|
||||
mainList({ key: $('#key').val() });
|
||||
}
|
||||
, btnRefresh: function () {
|
||||
mainList();
|
||||
}
|
||||
};
|
||||
|
||||
$('.toolList .layui-btn').on('click', function () {
|
||||
var type = $(this).data('type');
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
|
||||
//监听页面主按钮操作 end
|
||||
})
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
<%--
|
||||
Author: yubaolee
|
||||
Description: 用于生成OpenAuth.Core开源版前端Web界面,包括mvc controller/csthml/js
|
||||
--%>
|
||||
<%@ Template Language="C#" TargetLanguage="Text" Debug="True" OutputType="None" %>
|
||||
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Assembly Name="CodeSmith.CustomProperties" %>
|
||||
|
||||
<%@ Assembly Name="Mono.Cecil" Path="..\Common" %>
|
||||
<%@ Assembly Name="ICSharpCode.NRefactory" Path="..\Common" %>
|
||||
<%@ Assembly Name="ICSharpCode.NRefactory.CSharp" Path="..\Common" %>
|
||||
|
||||
<%@ Assembly Src="Internal\Model.cs" %>
|
||||
<%@ Assembly Src="Internal\Extensions.cs" %>
|
||||
<%@ Assembly Src="Internal\Generator.cs" %>
|
||||
<%@ Assembly Src="Internal\Parser.cs" %>
|
||||
|
||||
<%@ Import Namespace="System.Collections.Generic" %>
|
||||
<%@ Import Namespace="System.IO" %>
|
||||
<%@ Import Namespace="System.Linq" %>
|
||||
<%@ Import Namespace="System.Text" %>
|
||||
<%@ Import Namespace="System.Text.RegularExpressions" %>
|
||||
|
||||
<%@ Import Namespace="SchemaMapper" %>
|
||||
|
||||
<%@ Property Name="SourceTable"
|
||||
Type="SchemaExplorer.TableSchema"
|
||||
Category="Context"
|
||||
Description="连接的数据库"
|
||||
OnChanged="OnSourceDatabaseChanged"%>
|
||||
|
||||
<%@ Property Name="ModuleName"
|
||||
Type="System.String"
|
||||
Description="模块名称,如:User"%>
|
||||
<%@ Property Name="directory"
|
||||
Type="System.String"
|
||||
Default=".\"
|
||||
Optional="True"
|
||||
Description="代码生成路径"
|
||||
Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>
|
||||
|
||||
<%@ Register Name="HtmlGenerateClass"
|
||||
Template="Web\Index.cshtml.cst"
|
||||
MergeProperties="False" %>
|
||||
<%@ Register Name="JSGenerateClass"
|
||||
Template="Web\index.js.cst"
|
||||
MergeProperties="False" %>
|
||||
<%@ Register Name="ControllerGenerateClass"
|
||||
Template="Web\Controller.cst"
|
||||
MergeProperties="False" %>
|
||||
Generating Entities ...
|
||||
<% Generate(); %>
|
||||
|
||||
<script runat="template">
|
||||
public void Generate()
|
||||
{
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
string outputDirectory = Path.GetFullPath(directory);
|
||||
|
||||
CreateControllerClass();
|
||||
CreateHtmlClass();
|
||||
CreateJSClass();
|
||||
|
||||
this.RegisterReference("System.Configuration");
|
||||
this.RegisterReference("System.Data");
|
||||
this.RegisterReference("System.Data.Entity");
|
||||
this.RegisterReference("System.Runtime.Serialization");
|
||||
this.RegisterReference("EntityFramework");
|
||||
|
||||
watch.Stop();
|
||||
Response.WriteLine("Generate Time: " + watch.ElapsedMilliseconds + " ms");
|
||||
}
|
||||
|
||||
//创建控制器,如UserManagerController.cs
|
||||
public void CreateControllerClass()
|
||||
{
|
||||
ControllerGenerateClass generatedClass = this.Create<ControllerGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
string rootDirectory = Path.GetFullPath(directory);
|
||||
|
||||
string generatedFile = Path.GetFullPath(directory) + "/Controllers/"+ ModuleName + "sController.cs";
|
||||
|
||||
generatedClass.ModuleName = ModuleName;
|
||||
|
||||
Response.WriteLine(generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
|
||||
|
||||
//创建视图,如views/Users/index.html
|
||||
public void CreateHtmlClass()
|
||||
{
|
||||
HtmlGenerateClass generatedClass = this.Create<HtmlGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
string generatedFile = Path.GetFullPath(directory) + "/Views/"+ModuleName+"s/index.cshtml";
|
||||
|
||||
generatedClass.ModuleName = ModuleName;
|
||||
generatedClass.SourceTable = SourceTable;
|
||||
|
||||
Response.WriteLine(generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
|
||||
//创建视图,如js/userManager.js
|
||||
public void CreateJSClass()
|
||||
{
|
||||
JSGenerateClass generatedClass = this.Create<JSGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
string generatedFile = Path.GetFullPath(directory) + "/userJs/"+ModuleName.ToLower()+"s.js";
|
||||
|
||||
generatedClass.ModuleName = ModuleName;
|
||||
|
||||
Response.WriteLine(generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
|
||||
|
||||
//更换数据源时,改变ModuleName
|
||||
private void OnSourceDatabaseChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (SourceTable == null)
|
||||
return;
|
||||
ModuleName = SourceTable.Name;
|
||||
}
|
||||
|
||||
</script>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,36 @@
|
|||
##See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
#FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||
#WORKDIR /app
|
||||
#EXPOSE 10010
|
||||
#
|
||||
#COPY . .
|
||||
#ENV ASPNETCORE_URLS=http://+:10010
|
||||
#ENTRYPOINT ["dotnet", "/app/OpenAuth.WebApi.dll"]
|
||||
|
||||
|
||||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 10010
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["OpenAuth.WebApi/OpenAuth.WebApi.csproj", "OpenAuth.WebApi/"]
|
||||
COPY ["Infrastructure/Infrastructure.csproj", "Infrastructure/"]
|
||||
COPY ["OpenAuth.App/OpenAuth.App.csproj", "OpenAuth.App/"]
|
||||
COPY ["OpenAuth.Repository/OpenAuth.Repository.csproj", "OpenAuth.Repository/"]
|
||||
RUN dotnet restore "OpenAuth.WebApi/OpenAuth.WebApi.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/OpenAuth.WebApi"
|
||||
RUN dotnet build "OpenAuth.WebApi.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "OpenAuth.WebApi.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENV ASPNETCORE_URLS=http://+:10010
|
||||
ENTRYPOINT ["dotnet", "OpenAuth.WebApi.dll"]
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置项
|
||||
/// </summary>
|
||||
public class AppSetting
|
||||
{
|
||||
|
||||
public AppSetting()
|
||||
{
|
||||
SSOPassport = "http://localhost:52789";
|
||||
Version = "";
|
||||
UploadPath = "";
|
||||
IdentityServerUrl = "";
|
||||
}
|
||||
/// <summary>
|
||||
/// SSO地址
|
||||
/// </summary>
|
||||
public string SSOPassport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 版本信息
|
||||
/// 如果为demo,则屏蔽Post请求
|
||||
/// </summary>
|
||||
public string Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库类型 SqlServer、MySql
|
||||
/// </summary>
|
||||
public Dictionary<string, string> DbTypes { get; set; }
|
||||
|
||||
/// <summary> 附件上传路径</summary>
|
||||
public string UploadPath { get; set; }
|
||||
|
||||
//identity授权的地址
|
||||
public string IdentityServerUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Redis服务器配置
|
||||
/// </summary>
|
||||
//public string RedisConf { get; set; }
|
||||
public RedisConf RedisConf { get; set; }
|
||||
|
||||
//是否是Identity授权方式
|
||||
public bool IsIdentityAuth => !string.IsNullOrEmpty(IdentityServerUrl);
|
||||
}
|
||||
|
||||
public class RedisConf
|
||||
{
|
||||
public string Conn { get; set; }
|
||||
public int Database { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : FairUtility
|
||||
// Author : Yubao Li
|
||||
// Created : 08-27-2015
|
||||
//
|
||||
// Last Modified By : Yubao Li
|
||||
// Last Modified On : 08-27-2015
|
||||
// ***********************************************************************
|
||||
// <copyright file="AutoMapperExt.cs" company="">
|
||||
// Copyright (c) . All rights reserved.
|
||||
// </copyright>
|
||||
// <summary></summary>
|
||||
// ***********************************************************************
|
||||
|
||||
using System;
|
||||
using AutoMapper;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public static class AutoMapperExt
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型映射
|
||||
/// </summary>
|
||||
public static T MapTo<T>(this object obj)
|
||||
{
|
||||
if (obj == null) return default(T);
|
||||
|
||||
var config = new MapperConfiguration(cfg=>cfg.CreateMap(obj.GetType(),typeof(T)));
|
||||
var mapper = config.CreateMapper();
|
||||
return mapper.Map<T>(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 集合列表类型映射
|
||||
/// </summary>
|
||||
public static List<TDestination> MapToList<TDestination>(this IEnumerable source)
|
||||
{
|
||||
Type sourceType = source.GetType().GetGenericArguments()[0]; //获取枚举的成员类型
|
||||
var config = new MapperConfiguration(cfg => cfg.CreateMap(sourceType, typeof(TDestination)));
|
||||
var mapper = config.CreateMapper();
|
||||
|
||||
return mapper.Map<List<TDestination>>(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 集合列表类型映射
|
||||
/// </summary>
|
||||
public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source)
|
||||
{
|
||||
var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(TSource), typeof(TDestination)));
|
||||
var mapper = config.CreateMapper();
|
||||
|
||||
return mapper.Map<List<TDestination>>(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 类型映射
|
||||
/// </summary>
|
||||
public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination)
|
||||
where TSource : class
|
||||
where TDestination : class
|
||||
{
|
||||
if (source == null) return destination;
|
||||
|
||||
var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(TSource), typeof(TDestination)));
|
||||
var mapper = config.CreateMapper();
|
||||
return mapper.Map<TDestination>(source);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : Helper
|
||||
// Author : yubaolee
|
||||
// Created : 12-16-2016
|
||||
//
|
||||
// Last Modified By : yubaolee
|
||||
// Last Modified On : 12-21-2016
|
||||
// 使用微软默认带超时的Cache
|
||||
// File: CacheContext.cs
|
||||
// ***********************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace Infrastructure.Cache
|
||||
{
|
||||
public class CacheContext : ICacheContext
|
||||
{
|
||||
private IMemoryCache _objCache;
|
||||
private static readonly ConcurrentDictionary<string, ConcurrentQueue<string>> queueDic = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
public CacheContext(IMemoryCache objCache)
|
||||
{
|
||||
_objCache = objCache;
|
||||
}
|
||||
|
||||
public override T Get<T>(string key)
|
||||
{
|
||||
return _objCache.Get<T>(key);
|
||||
}
|
||||
|
||||
public override bool Set<T>(string key, T t, DateTime expire)
|
||||
{
|
||||
var obj = Get<T>(key);
|
||||
if (obj != null)
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
|
||||
_objCache.Set(key, t, new MemoryCacheEntryOptions()
|
||||
.SetAbsoluteExpiration(expire)); //绝对过期时间
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Remove(string key)
|
||||
{
|
||||
_objCache.Remove(key);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加并发锁
|
||||
/// </summary>
|
||||
/// <param name="id">值</param>
|
||||
/// <param name="func">执行方法</param>
|
||||
/// <param name="key">键</param>
|
||||
/// <returns></returns>
|
||||
public override async Task<T> Lock<T>(string id, Func<string, Task<T>> func, string key = "hc")
|
||||
{
|
||||
var queue = queueDic.GetOrAdd(id, new ConcurrentQueue<string>());
|
||||
var token = Guid.NewGuid().ToString();
|
||||
queue.Enqueue(token);
|
||||
queue.TryPeek(out string newToken);
|
||||
if (token != newToken)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
queue.TryPeek(out newToken);
|
||||
if (token == newToken)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await func(id);
|
||||
}
|
||||
finally
|
||||
{
|
||||
queue.TryDequeue(out string _);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : Infrastructure
|
||||
// Author : yubaolee
|
||||
// Created : 06-21-2016
|
||||
//
|
||||
// Last Modified By : yubaolee
|
||||
// Last Modified On : 06-21-2016
|
||||
// Contact : Add services.AddEnyimMemcached(...)
|
||||
// and app.UseEnyimMemcached() in Startup.
|
||||
// File: EnyimMemcachedContext.cs
|
||||
// ***********************************************************************
|
||||
|
||||
|
||||
|
||||
using System;
|
||||
using Enyim.Caching;
|
||||
using Enyim.Caching.Memcached;
|
||||
|
||||
namespace Infrastructure.Cache
|
||||
{
|
||||
public sealed class EnyimMemcachedContext : ICacheContext
|
||||
{
|
||||
private IMemcachedClient _memcachedClient;
|
||||
|
||||
public EnyimMemcachedContext(IMemcachedClient client)
|
||||
{
|
||||
_memcachedClient = client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public override T Get<T>(string key)
|
||||
{
|
||||
return _memcachedClient.Get<T>(key);
|
||||
}
|
||||
|
||||
public override bool Set<T>(string key, T t, DateTime expire)
|
||||
{
|
||||
return _memcachedClient.Store(StoreMode.Set, key, t, expire);
|
||||
}
|
||||
|
||||
public override bool Remove(string key)
|
||||
{
|
||||
return _memcachedClient.Remove(key);
|
||||
}
|
||||
public override Task<T> Lock<T>(string id, Func<string, Task<T>> func, string key = "hc")
|
||||
{
|
||||
return func(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
|
||||
namespace Infrastructure.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存接口
|
||||
/// </summary>
|
||||
public abstract class ICacheContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取缓存项
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存对象类型</typeparam>
|
||||
/// <param name="key">键</param>
|
||||
/// <returns>缓存对象</returns>
|
||||
public abstract T Get<T>(string key);
|
||||
|
||||
/// <summary>
|
||||
/// 设置缓存项
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存对象类型</typeparam>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="t">缓存对象</param>
|
||||
/// <returns>true成功,false失败</returns>
|
||||
public abstract bool Set<T>(string key, T t, DateTime expire);
|
||||
|
||||
/// <summary>
|
||||
/// 移除一个缓存项
|
||||
/// </summary>
|
||||
/// <param name="key">缓存项key</param>
|
||||
/// <returns>true成功,false失败</returns>
|
||||
public abstract bool Remove(string key);
|
||||
public abstract Task<T> Lock<T>(string id, Func<string, Task<T>> func, string key = "hc");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using Enyim.Caching;
|
||||
using Enyim.Caching.Memcached;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Infrastructure.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存redis实现
|
||||
/// </summary>
|
||||
public sealed class RedisCacheContext : ICacheContext
|
||||
{
|
||||
private ConnectionMultiplexer _conn { get; set; }
|
||||
private IDatabase iDatabase { get; set; }
|
||||
|
||||
public RedisCacheContext(IOptions<AppSetting> options)
|
||||
{
|
||||
_conn = ConnectionMultiplexer.Connect(options.Value.RedisConf.Conn);
|
||||
iDatabase = _conn.GetDatabase(options.Value.RedisConf.Database);
|
||||
}
|
||||
|
||||
public override T Get<T>(string key)
|
||||
{
|
||||
RedisValue value = iDatabase.StringGet(key);
|
||||
if (!value.HasValue)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
return (T)Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
return JsonHelper.Instance.Deserialize<T>(value);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Set<T>(string key, T t, DateTime expire)
|
||||
{
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
return iDatabase.StringSet(key, t.ToString(), expire - DateTime.Now);
|
||||
}
|
||||
else
|
||||
{
|
||||
return iDatabase.StringSet(key, JsonHelper.Instance.Serialize(t), expire - DateTime.Now);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Remove(string key)
|
||||
{
|
||||
return iDatabase.KeyDelete(key);
|
||||
}
|
||||
|
||||
public override Task<T> Lock<T>(string id, Func<string, Task<T>> func, string key = "hc")
|
||||
{
|
||||
return func(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public class CommonException : Exception
|
||||
{
|
||||
private int _code;
|
||||
|
||||
public CommonException(string message, int code)
|
||||
: base(message)
|
||||
{
|
||||
this._code = code;
|
||||
}
|
||||
|
||||
public int Code
|
||||
{
|
||||
get { return _code; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程状态
|
||||
/// </summary>
|
||||
public struct FlowInstanceStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 撤销、召回
|
||||
/// </summary>
|
||||
public const int Draft = -1;
|
||||
/// <summary>
|
||||
/// 正在运行
|
||||
/// </summary>
|
||||
public const int Running = 0;
|
||||
/// <summary>
|
||||
/// 完成
|
||||
/// </summary>
|
||||
public const int Finished = 1;
|
||||
/// <summary>
|
||||
/// 不同意
|
||||
/// </summary>
|
||||
public const int Disagree = 3;
|
||||
/// <summary>
|
||||
/// 驳回
|
||||
/// </summary>
|
||||
public const int Rejected = 4;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
public struct HtmlElementType
|
||||
{
|
||||
public const string drop = "drop";
|
||||
public const string droplist = "droplist";
|
||||
public const string select = "select";
|
||||
public const string selectlist = "selectlist";
|
||||
public const string checkbox = "checkbox";
|
||||
public const string textarea = "textarea";
|
||||
public const string thanorequal = "thanorequal";
|
||||
public const string lessorequal = "lessorequal";
|
||||
|
||||
|
||||
public const string gt = "gt";
|
||||
public const string lt = "lt";
|
||||
public const string GT = ">";
|
||||
public const string LT = "<";
|
||||
public const string like = "like";
|
||||
|
||||
public const string ThanOrEqual = ">=";
|
||||
public const string LessOrequal = "<=";
|
||||
public const string Contains = "in";
|
||||
public const string Equal = "=";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
/// <summary>
|
||||
/// 定时任务状态
|
||||
/// </summary>
|
||||
public enum JobStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 未启动
|
||||
/// </summary>
|
||||
NotRun,
|
||||
/// <summary>
|
||||
/// 正在运行
|
||||
/// </summary>
|
||||
Running
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
public enum LinqExpressionType
|
||||
{
|
||||
Equal=0,//=
|
||||
NotEqual=1,//!=
|
||||
GreaterThan,//>
|
||||
LessThan,//<
|
||||
ThanOrEqual,//>=
|
||||
LessThanOrEqual,//<=
|
||||
In,
|
||||
Contains,//Contains
|
||||
NotContains//NotContains
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
public enum QueryOrderBy
|
||||
{
|
||||
Desc=1,
|
||||
Asc=2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
public enum ResponseType
|
||||
{
|
||||
ServerError = 1,
|
||||
LoginExpiration = 302,
|
||||
ParametersLack = 303,
|
||||
TokenExpiration,
|
||||
PINError,
|
||||
NoPermissions,
|
||||
NoRolePermissions,
|
||||
LoginError,
|
||||
AccountLocked,
|
||||
LoginSuccess,
|
||||
SaveSuccess,
|
||||
AuditSuccess,
|
||||
OperSuccess,
|
||||
RegisterSuccess,
|
||||
ModifyPwdSuccess,
|
||||
EidtSuccess,
|
||||
DelSuccess,
|
||||
NoKey,
|
||||
NoKeyDel,
|
||||
KeyError,
|
||||
Other
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace Infrastructure.Const
|
||||
{
|
||||
public struct SqlDbTypeName
|
||||
{
|
||||
public const string NVarChar = "nvarchar";
|
||||
public const string VarChar = "varchar";
|
||||
public const string NChar = "nchar";
|
||||
public const string Char = "char";
|
||||
public const string Text = "text";
|
||||
public const string Int = "int";
|
||||
public const string BigInt = "bigint";
|
||||
public const string DateTime = "datetime";
|
||||
public const string Date = "date";
|
||||
public const string SmallDateTime = "smalldatetime";
|
||||
public const string SmallDate = "smalldate";
|
||||
public const string Float = "float";
|
||||
public const string Decimal = "decimal";
|
||||
public const string Double = "double";
|
||||
public const string Bit = "bit";
|
||||
public const string Bool = "bool";
|
||||
public const string UniqueIdentifier = "uniqueidentifier";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,412 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Infrastructure.Extensions;
|
||||
|
||||
namespace Infrastructure.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库数据转换拓展
|
||||
/// </summary>
|
||||
public static class DbDataConvertExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 将 DataTable 转 List 集合
|
||||
/// </summary>
|
||||
/// <typeparam name="T">返回值类型</typeparam>
|
||||
/// <param name="dataTable">DataTable</param>
|
||||
/// <returns>List{T}</returns>
|
||||
public static List<T> ToList<T>(this DataTable dataTable)
|
||||
{
|
||||
return dataTable.ToList(typeof(List<T>)) as List<T>;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataTable 转 List 集合
|
||||
/// </summary>
|
||||
/// <typeparam name="T">返回值类型</typeparam>
|
||||
/// <param name="dataTable">DataTable</param>
|
||||
/// <returns>List{T}</returns>
|
||||
public static async Task<List<T>> ToListAsync<T>(this DataTable dataTable)
|
||||
{
|
||||
var list = await dataTable.ToListAsync(typeof(List<T>));
|
||||
return list as List<T>;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static List<T1> ToList<T1>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>));
|
||||
return tuple[0] as List<T1>;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2) ToList<T1, T2>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <typeparam name="T3">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2, List<T3> list3) ToList<T1, T2, T3>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>), typeof(List<T3>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>, tuple[2] as List<T3>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <typeparam name="T3">元组元素类型</typeparam>
|
||||
/// <typeparam name="T4">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2, List<T3> list3, List<T4> list4) ToList<T1, T2, T3, T4>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>), typeof(List<T3>), typeof(List<T4>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>, tuple[2] as List<T3>, tuple[3] as List<T4>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <typeparam name="T3">元组元素类型</typeparam>
|
||||
/// <typeparam name="T4">元组元素类型</typeparam>
|
||||
/// <typeparam name="T5">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2, List<T3> list3, List<T4> list4, List<T5> list5) ToList<T1, T2, T3, T4, T5>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>), typeof(List<T3>), typeof(List<T4>), typeof(List<T5>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>, tuple[2] as List<T3>, tuple[3] as List<T4>, tuple[4] as List<T5>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <typeparam name="T3">元组元素类型</typeparam>
|
||||
/// <typeparam name="T4">元组元素类型</typeparam>
|
||||
/// <typeparam name="T5">元组元素类型</typeparam>
|
||||
/// <typeparam name="T6">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2, List<T3> list3, List<T4> list4, List<T5> list5, List<T6> list6) ToList<T1, T2, T3, T4, T5, T6>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>), typeof(List<T3>), typeof(List<T4>), typeof(List<T5>), typeof(List<T6>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>, tuple[2] as List<T3>, tuple[3] as List<T4>, tuple[4] as List<T5>, tuple[5] as List<T6>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <typeparam name="T3">元组元素类型</typeparam>
|
||||
/// <typeparam name="T4">元组元素类型</typeparam>
|
||||
/// <typeparam name="T5">元组元素类型</typeparam>
|
||||
/// <typeparam name="T6">元组元素类型</typeparam>
|
||||
/// <typeparam name="T7">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2, List<T3> list3, List<T4> list4, List<T5> list5, List<T6> list6, List<T7> list7) ToList<T1, T2, T3, T4, T5, T6, T7>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>), typeof(List<T3>), typeof(List<T4>), typeof(List<T5>), typeof(List<T6>), typeof(List<T7>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>, tuple[2] as List<T3>, tuple[3] as List<T4>, tuple[4] as List<T5>, tuple[5] as List<T6>, tuple[6] as List<T7>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">元组元素类型</typeparam>
|
||||
/// <typeparam name="T2">元组元素类型</typeparam>
|
||||
/// <typeparam name="T3">元组元素类型</typeparam>
|
||||
/// <typeparam name="T4">元组元素类型</typeparam>
|
||||
/// <typeparam name="T5">元组元素类型</typeparam>
|
||||
/// <typeparam name="T6">元组元素类型</typeparam>
|
||||
/// <typeparam name="T7">元组元素类型</typeparam>
|
||||
/// <typeparam name="T8">元组元素类型</typeparam>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <returns>元组类型</returns>
|
||||
public static (List<T1> list1, List<T2> list2, List<T3> list3, List<T4> list4, List<T5> list5, List<T6> list6, List<T7> list7, List<T8> list8) ToList<T1, T2, T3, T4, T5, T6, T7, T8>(this DataSet dataSet)
|
||||
{
|
||||
var tuple = dataSet.ToList(typeof(List<T1>), typeof(List<T2>), typeof(List<T3>), typeof(List<T4>), typeof(List<T5>), typeof(List<T6>), typeof(List<T7>), typeof(List<T8>));
|
||||
return (tuple[0] as List<T1>, tuple[1] as List<T2>, tuple[2] as List<T3>, tuple[3] as List<T4>, tuple[4] as List<T5>, tuple[5] as List<T6>, tuple[6] as List<T7>, tuple[7] as List<T8>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 特定类型
|
||||
/// </summary>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <param name="returnTypes">特定类型集合</param>
|
||||
/// <returns>List{object}</returns>
|
||||
public static List<object> ToList(this DataSet dataSet, params Type[] returnTypes)
|
||||
{
|
||||
if (returnTypes == null || returnTypes.Length == 0) return default;
|
||||
|
||||
// 处理元组类型
|
||||
if (returnTypes.Length == 1 && returnTypes[0].IsValueType)
|
||||
{
|
||||
returnTypes = returnTypes[0].GenericTypeArguments;
|
||||
}
|
||||
|
||||
// 获取所有的 DataTable
|
||||
var dataTables = dataSet.Tables;
|
||||
|
||||
// 处理 8 个结果集
|
||||
if (returnTypes.Length >= 8)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1]),
|
||||
dataTables[2].ToList(returnTypes[2]),
|
||||
dataTables[3].ToList(returnTypes[3]),
|
||||
dataTables[4].ToList(returnTypes[4]),
|
||||
dataTables[5].ToList(returnTypes[5]),
|
||||
dataTables[6].ToList(returnTypes[6]),
|
||||
dataTables[7].ToList(returnTypes[7])
|
||||
};
|
||||
}
|
||||
// 处理 7 个结果集
|
||||
else if (returnTypes.Length == 7)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1]),
|
||||
dataTables[2].ToList(returnTypes[2]),
|
||||
dataTables[3].ToList(returnTypes[3]),
|
||||
dataTables[4].ToList(returnTypes[4]),
|
||||
dataTables[5].ToList(returnTypes[5]),
|
||||
dataTables[6].ToList(returnTypes[6])
|
||||
};
|
||||
}
|
||||
// 处理 6 个结果集
|
||||
else if (returnTypes.Length == 6)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1]),
|
||||
dataTables[2].ToList(returnTypes[2]),
|
||||
dataTables[3].ToList(returnTypes[3]),
|
||||
dataTables[4].ToList(returnTypes[4]),
|
||||
dataTables[5].ToList(returnTypes[5])
|
||||
};
|
||||
}
|
||||
// 处理 5 个结果集
|
||||
else if (returnTypes.Length == 5)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1]),
|
||||
dataTables[2].ToList(returnTypes[2]),
|
||||
dataTables[3].ToList(returnTypes[3]),
|
||||
dataTables[4].ToList(returnTypes[4])
|
||||
};
|
||||
}
|
||||
// 处理 4 个结果集
|
||||
else if (returnTypes.Length == 4)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1]),
|
||||
dataTables[2].ToList(returnTypes[2]),
|
||||
dataTables[3].ToList(returnTypes[3])
|
||||
};
|
||||
}
|
||||
// 处理 3 个结果集
|
||||
else if (returnTypes.Length == 3)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1]),
|
||||
dataTables[2].ToList(returnTypes[2])
|
||||
};
|
||||
}
|
||||
// 处理 2 个结果集
|
||||
else if (returnTypes.Length == 2)
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0]),
|
||||
dataTables[1].ToList(returnTypes[1])
|
||||
};
|
||||
}
|
||||
// 处理 1 个结果集
|
||||
else
|
||||
{
|
||||
return new List<object>
|
||||
{
|
||||
dataTables[0].ToList(returnTypes[0])
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataSet 转 特定类型
|
||||
/// </summary>
|
||||
/// <param name="dataSet">DataSet</param>
|
||||
/// <param name="returnTypes">特定类型集合</param>
|
||||
/// <returns>object</returns>
|
||||
public static Task<List<object>> ToListAsync(this DataSet dataSet, params Type[] returnTypes)
|
||||
{
|
||||
return Task.FromResult(dataSet.ToList(returnTypes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataTable 转 特定类型
|
||||
/// </summary>
|
||||
/// <param name="dataTable">DataTable</param>
|
||||
/// <param name="returnType">返回值类型</param>
|
||||
/// <returns>object</returns>
|
||||
public static object ToList(this DataTable dataTable, Type returnType)
|
||||
{
|
||||
var isGenericType = returnType.IsGenericType;
|
||||
// 获取类型真实返回类型
|
||||
var underlyingType = isGenericType ? returnType.GenericTypeArguments.First() : returnType;
|
||||
|
||||
var resultType = typeof(List<>).MakeGenericType(underlyingType);
|
||||
var list = Activator.CreateInstance(resultType);
|
||||
var addMethod = resultType.GetMethod("Add");
|
||||
|
||||
// 将 DataTable 转为行集合
|
||||
var dataRows = dataTable.AsEnumerable();
|
||||
|
||||
// 如果是基元类型
|
||||
if (underlyingType.IsRichPrimitive())
|
||||
{
|
||||
// 遍历所有行
|
||||
foreach (var dataRow in dataRows)
|
||||
{
|
||||
// 只取第一列数据
|
||||
var firstColumnValue = dataRow[0];
|
||||
// 转换成目标类型数据
|
||||
var destValue = firstColumnValue?.ChangeType(underlyingType);
|
||||
// 添加到集合中
|
||||
_ = addMethod.Invoke(list, new[] { destValue });
|
||||
}
|
||||
}
|
||||
// 处理Object类型
|
||||
else if (underlyingType == typeof(object))
|
||||
{
|
||||
// 获取所有列名
|
||||
var columns = dataTable.Columns;
|
||||
|
||||
// 遍历所有行
|
||||
foreach (var dataRow in dataRows)
|
||||
{
|
||||
var dic = new Dictionary<string, object>();
|
||||
foreach (DataColumn column in columns)
|
||||
{
|
||||
dic.Add(column.ColumnName, dataRow[column]);
|
||||
}
|
||||
_ = addMethod.Invoke(list, new[] { dic });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取所有的数据列和类公开实例属性
|
||||
var dataColumns = dataTable.Columns;
|
||||
var properties = underlyingType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
//.Where(p => !p.IsDefined(typeof(NotMappedAttribute), true)); // sql 数据转换无需判断 [NotMapperd] 特性
|
||||
|
||||
// 遍历所有行
|
||||
foreach (var dataRow in dataRows)
|
||||
{
|
||||
var model = Activator.CreateInstance(underlyingType);
|
||||
|
||||
// 遍历所有属性并一一赋值
|
||||
foreach (var property in properties)
|
||||
{
|
||||
// 获取属性对应的真实列名
|
||||
var columnName = property.Name;
|
||||
if (property.IsDefined(typeof(ColumnAttribute), true))
|
||||
{
|
||||
var columnAttribute = property.GetCustomAttribute<ColumnAttribute>(true);
|
||||
if (!string.IsNullOrWhiteSpace(columnAttribute.Name)) columnName = columnAttribute.Name;
|
||||
}
|
||||
|
||||
// 如果 DataTable 不包含该列名,则跳过
|
||||
if (!dataColumns.Contains(columnName)) continue;
|
||||
|
||||
// 获取列值
|
||||
var columnValue = dataRow[columnName];
|
||||
// 如果列值未空,则跳过
|
||||
if (columnValue == DBNull.Value) continue;
|
||||
|
||||
// 转换成目标类型数据
|
||||
var destValue = columnValue?.ChangeType(property.PropertyType);
|
||||
property.SetValue(model, destValue);
|
||||
}
|
||||
|
||||
// 添加到集合中
|
||||
_ = addMethod.Invoke(list, new[] { model });
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 DataTable 转 特定类型
|
||||
/// </summary>
|
||||
/// <param name="dataTable">DataTable</param>
|
||||
/// <param name="returnType">返回值类型</param>
|
||||
/// <returns>object</returns>
|
||||
public static Task<object> ToListAsync(this DataTable dataTable, Type returnType)
|
||||
{
|
||||
return Task.FromResult(dataTable.ToList(returnType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理元组类型返回值
|
||||
/// </summary>
|
||||
/// <param name="dataSet">数据集</param>
|
||||
/// <param name="tupleType">返回值类型</param>
|
||||
/// <returns></returns>
|
||||
internal static object ToValueTuple(this DataSet dataSet, Type tupleType)
|
||||
{
|
||||
// 获取元组最底层类型
|
||||
var underlyingTypes = tupleType.GetGenericArguments().Select(u => u.IsGenericType ? u.GetGenericArguments().First() : u);
|
||||
|
||||
var toListMethod = typeof(DbDataConvertExtensions)
|
||||
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
||||
.First(u => u.Name == "ToList" && u.IsGenericMethod && u.GetGenericArguments().Length == tupleType.GetGenericArguments().Length)
|
||||
.MakeGenericMethod(underlyingTypes.ToArray());
|
||||
|
||||
return toListMethod.Invoke(null, new[] { dataSet });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
namespace Infrastructure
|
||||
{
|
||||
public static class Define
|
||||
{
|
||||
public static string USERROLE = "UserRole"; //用户角色关联KEY
|
||||
public const string ROLERESOURCE = "RoleResource"; //角色资源关联KEY
|
||||
public const string USERORG = "UserOrg"; //用户机构关联KEY
|
||||
public const string ROLEELEMENT = "RoleElement"; //角色菜单关联KEY
|
||||
public const string ROLEMODULE = "RoleModule"; //角色模块关联KEY
|
||||
public const string ROLEDATAPROPERTY = "RoleDataProperty"; //角色数据字段权限
|
||||
|
||||
|
||||
public const string DBTYPE_SQLSERVER = "SqlServer"; //sql server
|
||||
public const string DBTYPE_MYSQL = "MySql"; //mysql
|
||||
public const string DBTYPE_PostgreSQL = "PostgreSQL"; //PostgreSQL
|
||||
public const string DBTYPE_ORACLE = "Oracle"; //oracle
|
||||
|
||||
|
||||
public const int INVALID_TOKEN = 50014; //token无效
|
||||
|
||||
public const string TOKEN_NAME = "X-Token";
|
||||
public const string TENANT_ID = "tenantId";
|
||||
|
||||
|
||||
public const string SYSTEM_USERNAME = "System";
|
||||
public const string SYSTEM_USERPWD = "acdcd3db09e0dc32c222c1840144e31d";
|
||||
//public const string SYSTEM_USERPWD = "6ff33dd3478bae96663aced32f5262fa";
|
||||
public const string SYSTEM_SECRETKEY = "b6467189772775db";
|
||||
|
||||
public const string DATAPRIVILEGE_LOGINUSER = "{loginUser}"; //数据权限配置中,当前登录用户的key
|
||||
public const string DATAPRIVILEGE_LOGINROLE = "{loginRole}"; //数据权限配置中,当前登录用户角色的key
|
||||
public const string DATAPRIVILEGE_LOGINORG = "{loginOrg}"; //数据权限配置中,当前登录用户部门的key
|
||||
|
||||
public const string JOBMAPKEY = "OpenJob";
|
||||
|
||||
public const string DEFAULT_FORM_INSTANCE_ID_NAME = "InstanceId";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : FairUtility
|
||||
// Author : Yubao Li
|
||||
// Created : 08-18-2015
|
||||
//
|
||||
// Last Modified By : Yubao Li
|
||||
// Last Modified On : 08-18-2015
|
||||
// ***********************************************************************
|
||||
// <copyright file="DynamicLinq.cs" company="">
|
||||
// Copyright (c) . All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>动态linq</summary>
|
||||
// ***********************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public static class DynamicLinq
|
||||
{
|
||||
public static ParameterExpression CreateLambdaParam<T>(string name)
|
||||
{
|
||||
return Expression.Parameter(typeof(T), name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建linq表达示的body部分
|
||||
/// </summary>
|
||||
public static Expression GenerateBody<T>(this ParameterExpression param, Filter filterObj)
|
||||
{
|
||||
PropertyInfo property = typeof(T).GetProperty(filterObj.Key);
|
||||
|
||||
Expression left = null; //组装左边
|
||||
//组装右边
|
||||
Expression right = null;
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
left = Expression.Property(param, property);
|
||||
if (property.PropertyType == typeof(int))
|
||||
{
|
||||
right = Expression.Constant(int.Parse(filterObj.Value));
|
||||
}
|
||||
else if (property.PropertyType == typeof(DateTime))
|
||||
{
|
||||
right = Expression.Constant(DateTime.Parse(filterObj.Value));
|
||||
}
|
||||
else if (property.PropertyType == typeof(string))
|
||||
{
|
||||
right = Expression.Constant(filterObj.Value);
|
||||
}
|
||||
else if (property.PropertyType == typeof(decimal))
|
||||
{
|
||||
right = Expression.Constant(decimal.Parse(filterObj.Value));
|
||||
}
|
||||
else if (property.PropertyType == typeof(Guid))
|
||||
{
|
||||
right = Expression.Constant(Guid.Parse(filterObj.Value));
|
||||
}
|
||||
else if (property.PropertyType == typeof(bool))
|
||||
{
|
||||
right = Expression.Constant(filterObj.Value.Equals("1"));
|
||||
}
|
||||
else if (property.PropertyType == typeof(Guid?))
|
||||
{
|
||||
left = Expression.Property(left, "Value");
|
||||
right = Expression.Constant(Guid.Parse(filterObj.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("暂不能解析该Key的类型");
|
||||
}
|
||||
}
|
||||
else //如果左边不是属性,直接是值的情况
|
||||
{
|
||||
left = Expression.Constant(filterObj.Key);
|
||||
right = Expression.Constant(filterObj.Value);
|
||||
}
|
||||
|
||||
//c.XXX=="XXX"
|
||||
Expression filter = Expression.Equal(left, right);
|
||||
switch (filterObj.Contrast)
|
||||
{
|
||||
case "<=":
|
||||
filter = Expression.LessThanOrEqual(left, right);
|
||||
break;
|
||||
|
||||
case "<":
|
||||
filter = Expression.LessThan(left, right);
|
||||
break;
|
||||
|
||||
case ">":
|
||||
filter = Expression.GreaterThan(left, right);
|
||||
break;
|
||||
|
||||
case ">=":
|
||||
filter = Expression.GreaterThanOrEqual(left, right);
|
||||
break;
|
||||
case "!=":
|
||||
filter = Expression.NotEqual(left, right);
|
||||
break;
|
||||
case "contains":
|
||||
filter = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] {typeof(string)}),
|
||||
Expression.Constant(filterObj.Value));
|
||||
break;
|
||||
case "in":
|
||||
var lExp = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组
|
||||
var methodInfo = typeof(List<string>).GetMethod("Contains",
|
||||
new Type[] {typeof(string)}); //Contains语句
|
||||
filter = Expression.Call(lExp, methodInfo, left);
|
||||
break;
|
||||
case "not in":
|
||||
var listExpression = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组
|
||||
var method = typeof(List<string>).GetMethod("Contains", new Type[] {typeof(string)}); //Contains语句
|
||||
filter = Expression.Not(Expression.Call(listExpression, method, left));
|
||||
break;
|
||||
//交集,使用交集时左值必须时固定的值
|
||||
case "intersect": //交集
|
||||
if (property != null)
|
||||
{
|
||||
throw new Exception("交集模式下,表达式左边不能为变量,请调整数据规则,如:c=>\"A,B,C\" intersect \"B,D\"");
|
||||
}
|
||||
|
||||
var rightval = filterObj.Value.Split(',').ToList();
|
||||
var leftval = filterObj.Key.Split(',').ToList();
|
||||
var val = rightval.Intersect(leftval);
|
||||
|
||||
filter = Expression.Constant(val.Count() > 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> GenerateTypeBody<T>(this ParameterExpression param, Filter filterObj)
|
||||
{
|
||||
return (Expression<Func<T, bool>>) (param.GenerateBody<T>(filterObj));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建完整的lambda
|
||||
/// </summary>
|
||||
public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body)
|
||||
{
|
||||
//c=>c.XXX=="XXX"
|
||||
return Expression.Lambda(body, param);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> GenerateTypeLambda<T>(this ParameterExpression param, Expression body)
|
||||
{
|
||||
return (Expression<Func<T, bool>>) (param.GenerateLambda(body));
|
||||
}
|
||||
|
||||
public static Expression AndAlso(this Expression expression, Expression expressionRight)
|
||||
{
|
||||
return Expression.AndAlso(expression, expressionRight);
|
||||
}
|
||||
|
||||
public static Expression Or(this Expression expression, Expression expressionRight)
|
||||
{
|
||||
return Expression.Or(expression, expressionRight);
|
||||
}
|
||||
|
||||
public static Expression And(this Expression expression, Expression expressionRight)
|
||||
{
|
||||
return Expression.And(expression, expressionRight);
|
||||
}
|
||||
|
||||
public static IQueryable<T> GenerateFilter<T>(this IQueryable<T> query, string parametername, string filterjson)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filterjson))
|
||||
{
|
||||
var filterGroup = JsonHelper.Instance.Deserialize<FilterGroup>(filterjson);
|
||||
query = GenerateFilter(query, parametername, filterGroup);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换FilterGroup为Lambda表达式
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="parametername"></param>
|
||||
/// <param name="filterGroup"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> GenerateFilter<T>(this IQueryable<T> query, string parametername,
|
||||
FilterGroup filterGroup)
|
||||
{
|
||||
var param = CreateLambdaParam<T>(parametername);
|
||||
Expression result = ConvertGroup<T>(filterGroup, param);
|
||||
query = query.Where(param.GenerateTypeLambda<T>(result));
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换filtergroup为表达式
|
||||
/// </summary>
|
||||
/// <param name="filterGroup"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression ConvertGroup<T>(FilterGroup filterGroup, ParameterExpression param)
|
||||
{
|
||||
if (filterGroup == null) return null;
|
||||
|
||||
if (filterGroup.Filters.Length == 1 &&(filterGroup.Children == null || !filterGroup.Children.Any())) //只有一个条件
|
||||
{
|
||||
return param.GenerateBody<T>(filterGroup.Filters[0]);
|
||||
}
|
||||
|
||||
Expression result = ConvertFilters<T>(filterGroup.Filters, param, filterGroup.Operation);
|
||||
Expression gresult = ConvertGroup<T>(filterGroup.Children, param, filterGroup.Operation);
|
||||
if (gresult == null) return result;
|
||||
if (result == null) return gresult;
|
||||
|
||||
if (filterGroup.Operation == "and")
|
||||
{
|
||||
return result.AndAlso(gresult);
|
||||
}
|
||||
else //or
|
||||
{
|
||||
return result.Or(gresult);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换FilterGroup[]为表达式,不管FilterGroup里面的Filters
|
||||
/// </summary>
|
||||
/// <param name="groups"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="operation"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
private static Expression ConvertGroup<T>(FilterGroup[] groups, ParameterExpression param, string operation)
|
||||
{
|
||||
if (groups == null || !groups.Any()) return null;
|
||||
|
||||
Expression result = ConvertGroup<T>(groups[0], param);
|
||||
|
||||
if (groups.Length == 1) return result;
|
||||
|
||||
if (operation == "and")
|
||||
{
|
||||
foreach (var filter in groups.Skip(1))
|
||||
{
|
||||
result = result.AndAlso(ConvertGroup<T>(filter, param));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var filter in groups.Skip(1))
|
||||
{
|
||||
result = result.Or(ConvertGroup<T>(filter, param));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换Filter数组为表达式
|
||||
/// </summary>
|
||||
/// <param name="filters"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="operation"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
private static Expression ConvertFilters<T>(Filter[] filters, ParameterExpression param, string operation)
|
||||
{
|
||||
if (filters == null || !filters.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Expression result = param.GenerateBody<T>(filters[0]);
|
||||
|
||||
if (filters.Length == 1)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (operation == "and")
|
||||
{
|
||||
foreach (var filter in filters.Skip(1))
|
||||
{
|
||||
result = result.AndAlso(param.GenerateBody<T>(filter));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var filter in filters.Skip(1))
|
||||
{
|
||||
result = result.Or(param.GenerateBody<T>(filter));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public class Encryption
|
||||
{
|
||||
private static string encryptKey = "4h!@w$rng,i#$@x1%)5^3(7*5P31/Ee0";
|
||||
|
||||
//默认密钥向量
|
||||
private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };
|
||||
/// <summary>
|
||||
/// 加密
|
||||
/// </summary>
|
||||
/// <param name="encryptString"></param>
|
||||
/// <returns></returns>
|
||||
public static string Encrypt(string encryptString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(encryptString))
|
||||
return string.Empty;
|
||||
RijndaelManaged rijndaelProvider = new RijndaelManaged();
|
||||
rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
|
||||
rijndaelProvider.IV = Keys;
|
||||
ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();
|
||||
|
||||
byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
|
||||
byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);
|
||||
|
||||
return Convert.ToBase64String(encryptedData);
|
||||
}
|
||||
/// <summary>
|
||||
/// 解密
|
||||
/// </summary>
|
||||
/// <param name="decryptString"></param>
|
||||
/// <returns></returns>
|
||||
public static string Decrypt(string decryptString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(decryptString))
|
||||
return string.Empty;
|
||||
try
|
||||
{
|
||||
RijndaelManaged rijndaelProvider = new RijndaelManaged();
|
||||
rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
|
||||
rijndaelProvider.IV = Keys;
|
||||
ICryptoTransform rijndaelDecrypt = rijndaelProvider.CreateDecryptor();
|
||||
|
||||
byte[] inputData = Convert.FromBase64String(decryptString);
|
||||
byte[] decryptedData = rijndaelDecrypt.TransformFinalBlock(inputData, 0, inputData.Length);
|
||||
|
||||
return Encoding.UTF8.GetString(decryptedData);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace Infrastructure.Extensions.AutofacManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供全局静态获取服务的能力。
|
||||
/// <para>例:AutofacContainerModule.GetService<IPathProvider>()</para>
|
||||
/// </summary>
|
||||
public class AutofacContainerModule
|
||||
{
|
||||
static private IServiceProvider _provider;
|
||||
public static void ConfigServiceProvider(IServiceProvider serviceProvider)
|
||||
{
|
||||
_provider = serviceProvider;
|
||||
}
|
||||
public static TService GetService<TService>() where TService:class
|
||||
{
|
||||
Type typeParameterType = typeof(TService);
|
||||
return (TService)_provider.GetService(typeParameterType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
namespace Infrastructure.Extensions.AutofacManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 所有AutoFac注入的基类
|
||||
/// </summary>
|
||||
public interface IDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,377 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class ConvertJsonExtension
|
||||
{
|
||||
#region 私有方法
|
||||
/// <summary>
|
||||
/// 过滤特殊字符
|
||||
/// </summary>
|
||||
/// <param name="s">字符串</param>
|
||||
/// <returns>json字符串</returns>
|
||||
private static string String2Json(String s)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
char c = s.ToCharArray()[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\"':
|
||||
sb.Append("\\\""); break;
|
||||
case '\\':
|
||||
sb.Append("\\\\"); break;
|
||||
case '/':
|
||||
sb.Append("\\/"); break;
|
||||
case '\b':
|
||||
sb.Append("\\b"); break;
|
||||
case '\f':
|
||||
sb.Append("\\f"); break;
|
||||
case '\n':
|
||||
sb.Append("\\n"); break;
|
||||
case '\r':
|
||||
sb.Append("\\r"); break;
|
||||
case '\t':
|
||||
sb.Append("\\t"); break;
|
||||
default:
|
||||
sb.Append(c); break;
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// 格式化字符型、日期型、布尔型
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static string StringFormat(string str, Type type)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
str = String2Json(str);
|
||||
str = "\"" + str + "\"";
|
||||
}
|
||||
else if (type == typeof(DateTime))
|
||||
{
|
||||
str = "\"" + str + "\"";
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
str = str.ToLower();
|
||||
}
|
||||
else if (type != typeof(string) && string.IsNullOrEmpty(str))
|
||||
{
|
||||
str = "\"" + str + "\"";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region list转换成JSON
|
||||
/// <summary>
|
||||
/// list转换为Json
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public static string ListToJson<T>(this IList<T> list)
|
||||
{
|
||||
object obj = list[0];
|
||||
return ListToJson<T>(list, obj.GetType().Name);
|
||||
}
|
||||
/// <summary>
|
||||
/// list转换为json
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="p"></param>
|
||||
/// <returns></returns>
|
||||
private static string ListToJson<T>(this IList<T> list, string JsonName)
|
||||
{
|
||||
if (list.Count == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
StringBuilder Json = new StringBuilder();
|
||||
if (string.IsNullOrEmpty(JsonName))
|
||||
JsonName = list[0].GetType().Name;
|
||||
Json.Append("{\"" + JsonName + "\":[");
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
T obj = Activator.CreateInstance<T>();
|
||||
PropertyInfo[] pi = obj.GetType().GetProperties();
|
||||
Json.Append("{");
|
||||
for (int j = 0; j < pi.Length; j++)
|
||||
{
|
||||
Type type = pi[j].GetValue(list[i], null).GetType();
|
||||
Json.Append("\"" + pi[j].Name.ToString() + "\":" + StringFormat(pi[j].GetValue(list[i], null).ToString(), type));
|
||||
if (j < pi.Length - 1)
|
||||
{
|
||||
Json.Append(",");
|
||||
}
|
||||
}
|
||||
Json.Append("}");
|
||||
if (i < list.Count - 1)
|
||||
{
|
||||
Json.Append(",");
|
||||
}
|
||||
}
|
||||
Json.Append("]}");
|
||||
return Json.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 对象转换为Json
|
||||
/// <summary>
|
||||
/// 对象转换为json
|
||||
/// </summary>
|
||||
/// <param name="jsonObject">json对象</param>
|
||||
/// <returns>json字符串</returns>
|
||||
public static string ToJson(this object jsonObject)
|
||||
{
|
||||
string jsonString = "{";
|
||||
PropertyInfo[] propertyInfo = jsonObject.GetType().GetProperties();
|
||||
for (int i = 0; i < propertyInfo.Length; i++)
|
||||
{
|
||||
object objectValue = propertyInfo[i].GetGetMethod().Invoke(jsonObject, null);
|
||||
string value = string.Empty;
|
||||
if (objectValue is DateTime || objectValue is Guid || objectValue is TimeSpan)
|
||||
{
|
||||
value = "'" + objectValue.ToString() + "'";
|
||||
}
|
||||
else if (objectValue is string)
|
||||
{
|
||||
value = "'" + ToJson(objectValue.ToString()) + "'";
|
||||
}
|
||||
else if (objectValue is IEnumerable)
|
||||
{
|
||||
value = ToJson((IEnumerable)objectValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ToJson(objectValue.ToString());
|
||||
}
|
||||
jsonString += "\"" + ToJson(propertyInfo[i].Name) + "\":" + value + ",";
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
|
||||
return jsonString + "}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 对象集合转换为json
|
||||
/// <summary>
|
||||
/// 对象集合转换为json
|
||||
/// </summary>
|
||||
/// <param name="array">对象集合</param>
|
||||
/// <returns>json字符串</returns>
|
||||
public static string ToJson(this IEnumerable array)
|
||||
{
|
||||
string jsonString = "{";
|
||||
foreach (object item in array)
|
||||
{
|
||||
jsonString += ToJson(item) + ",";
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
|
||||
return jsonString + "]";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 普通集合转换Json
|
||||
/// <summary>
|
||||
/// 普通集合转换Json
|
||||
/// </summary>
|
||||
/// <param name="array">集合对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ToArrayString(this IEnumerable array)
|
||||
{
|
||||
string jsonString = "[";
|
||||
foreach (object item in array)
|
||||
{
|
||||
jsonString = ToJson(item.ToString()) + ",";
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
|
||||
return jsonString + "]";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DataSet转换为Json
|
||||
/// <summary>
|
||||
/// DataSet转换为Json
|
||||
/// </summary>
|
||||
/// <param name="dataSet">DataSet对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ToJson(this DataSet dataSet)
|
||||
{
|
||||
string jsonString = "{";
|
||||
foreach (DataTable table in dataSet.Tables)
|
||||
{
|
||||
jsonString += "\"" + table.TableName + "\":" + ToJson(table) + ",";
|
||||
}
|
||||
jsonString = jsonString.TrimEnd(',');
|
||||
return jsonString + "}";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Datatable转换为Json
|
||||
/// <summary>
|
||||
/// Datatable转换为Json
|
||||
/// </summary>
|
||||
/// <param name="table">Datatable对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ToJson(this DataTable dt)
|
||||
{
|
||||
StringBuilder jsonString = new StringBuilder();
|
||||
jsonString.Append("[");
|
||||
DataRowCollection drc = dt.Rows;
|
||||
for (int i = 0; i < drc.Count; i++)
|
||||
{
|
||||
jsonString.Append("{");
|
||||
for (int j = 0; j < dt.Columns.Count; j++)
|
||||
{
|
||||
string strKey = dt.Columns[j].ColumnName;
|
||||
string strValue = drc[i][j].ToString();
|
||||
Type type = dt.Columns[j].DataType;
|
||||
jsonString.Append("\"" + strKey + "\":");
|
||||
strValue = StringFormat(strValue, type);
|
||||
if (j < dt.Columns.Count - 1)
|
||||
{
|
||||
jsonString.Append(strValue + ",");
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonString.Append(strValue);
|
||||
}
|
||||
}
|
||||
jsonString.Append("},");
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, 1);
|
||||
jsonString.Append("]");
|
||||
return jsonString.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// DataTable转换为Json
|
||||
/// </summary>
|
||||
public static string ToJson(this DataTable dt, string jsonName)
|
||||
{
|
||||
StringBuilder Json = new StringBuilder();
|
||||
if (string.IsNullOrEmpty(jsonName))
|
||||
jsonName = dt.TableName;
|
||||
Json.Append("{\"" + jsonName + "\":[");
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < dt.Rows.Count; i++)
|
||||
{
|
||||
Json.Append("{");
|
||||
for (int j = 0; j < dt.Columns.Count; j++)
|
||||
{
|
||||
Type type = dt.Rows[i][j].GetType();
|
||||
Json.Append("\"" + dt.Columns[j].ColumnName.ToString() + "\":" + StringFormat(dt.Rows[i][j].ToString(), type));
|
||||
if (j < dt.Columns.Count - 1)
|
||||
{
|
||||
Json.Append(",");
|
||||
}
|
||||
}
|
||||
Json.Append("}");
|
||||
if (i < dt.Rows.Count - 1)
|
||||
{
|
||||
Json.Append(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
Json.Append("]}");
|
||||
return Json.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DataReader转换为Json
|
||||
/// <summary>
|
||||
/// DataReader转换为Json
|
||||
/// </summary>
|
||||
/// <param name="dataReader">DataReader对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ReaderJson(this IDataReader dataReader)
|
||||
{
|
||||
StringBuilder jsonString = new StringBuilder();
|
||||
Dictionary<string, Type> ModelField = new Dictionary<string, Type>();
|
||||
for (int i = 0; i < dataReader.FieldCount; i++)
|
||||
{
|
||||
ModelField.Add(dataReader.GetName(i), dataReader.GetFieldType(i));
|
||||
}
|
||||
jsonString.Append("[");
|
||||
while (dataReader.Read())
|
||||
{
|
||||
jsonString.Append("{");
|
||||
foreach (KeyValuePair<string, Type> keyVal in ModelField)
|
||||
{
|
||||
Type type = keyVal.Value;
|
||||
string strKey = keyVal.Key;
|
||||
string strValue = dataReader[strKey].ToString();
|
||||
jsonString.Append("\"" + strKey + "\":");
|
||||
strValue = StringFormat(strValue, type);
|
||||
jsonString.Append(strValue + ",");
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, 1);
|
||||
jsonString.Append("},");
|
||||
}
|
||||
dataReader.Close();
|
||||
jsonString.Remove(jsonString.Length - 1, 1);
|
||||
jsonString.Append("]");
|
||||
return jsonString.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public static T DeserializeObject<T>(this string entityString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entityString))
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
if (entityString == "{}")
|
||||
{
|
||||
entityString = "[]";
|
||||
}
|
||||
return JsonConvert.DeserializeObject<T>(entityString);
|
||||
}
|
||||
|
||||
public static string Serialize(this object obj, JsonSerializerSettings formatDate = null)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
formatDate = formatDate ?? new JsonSerializerSettings
|
||||
{
|
||||
DateFormatString = "yyyy-MM-dd HH:mm:ss"
|
||||
};
|
||||
return JsonConvert.SerializeObject(obj, formatDate);
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 字串反序列化成指定对象实体(列表)
|
||||
//
|
||||
// 参数:
|
||||
// Json:
|
||||
// 字串
|
||||
//
|
||||
// 类型参数:
|
||||
// T:
|
||||
// 实体类型
|
||||
public static List<T> ToList<T>(this string Json)
|
||||
{
|
||||
return (Json == null) ? null : JsonConvert.DeserializeObject<List<T>>(Json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class DateTimeExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 实现由C# 的时间到 Javascript 的时间的转换
|
||||
/// returns the number of milliseconds since Jan 1, 1970 (useful for converting C# dates to JS dates)
|
||||
/// </summary>
|
||||
/// <param name="dt"></param>
|
||||
/// <returns></returns>
|
||||
public static double UnixTicks(this DateTime dt)
|
||||
{
|
||||
DateTime d1 = new DateTime(1970, 1, 1);
|
||||
DateTime d2 = dt.AddHours(8).ToUniversalTime();
|
||||
TimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks);
|
||||
return ts.TotalMilliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将毫秒值转成 C# DateTime 类型
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime ConvertTime(this long time)
|
||||
{
|
||||
DateTime timeStamp = new DateTime(1970, 1, 1); //得到1970年的时间戳
|
||||
long t = (time + 8 * 60 * 60) * 10000000 + timeStamp.Ticks;
|
||||
DateTime dt = new DateTime(t);
|
||||
return dt;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取格式化字符串,不带时分秒,格式:"yyyy-MM-dd"
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToDateString(this DateTime? dateTime)
|
||||
{
|
||||
if (!dateTime.HasValue)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return dateTime.Value.ToDateString();
|
||||
}
|
||||
public static string ToDateString(this DateTime dateTime)
|
||||
{
|
||||
return dateTime.ToString("yyyy-MM-dd");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class EnumTypeExtention
|
||||
{
|
||||
|
||||
public static T GetEnumByName<T>(this string name)
|
||||
{
|
||||
foreach (var memberInfo in typeof(T).GetMembers())
|
||||
{
|
||||
foreach (var attr in memberInfo.GetCustomAttributes(true))
|
||||
{
|
||||
var test = attr as DisplayAttribute;
|
||||
|
||||
if (test == null) continue;
|
||||
|
||||
if (test.Name == name)
|
||||
{
|
||||
var result = (T)Enum.Parse(typeof(T), memberInfo.Name);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public static string GetEnumName<T>(this T type, Enum enm) where T : Type
|
||||
{
|
||||
foreach (var memberInfo in type.GetMembers())
|
||||
{
|
||||
foreach (var attr in memberInfo.GetCustomAttributes(true))
|
||||
{
|
||||
var test = attr as DisplayAttribute;
|
||||
|
||||
if (test == null) continue;
|
||||
|
||||
if (memberInfo.Name == enm.ToString())
|
||||
{
|
||||
return test.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetDescription(this Enum val)
|
||||
{
|
||||
var field = val.GetType().GetField(val.ToString());
|
||||
var customAttribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));
|
||||
if (customAttribute == null) { return val.ToString(); }
|
||||
else { return ((DescriptionAttribute)customAttribute).Description; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class ExtensionsJson
|
||||
{
|
||||
//public static string ToJson(this object obj)
|
||||
//{
|
||||
// IsoDateTimeConverter isoDateTimeConverter = new IsoDateTimeConverter
|
||||
// {
|
||||
// DateTimeFormat = "yyyy-MM-dd HH:mm:ss"
|
||||
// };
|
||||
// return JsonConvert.SerializeObject(obj, isoDateTimeConverter);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 泛型扩展
|
||||
/// </summary>
|
||||
public static class GenericExtension
|
||||
{
|
||||
public static bool Equal<T>(this T x, T y)
|
||||
{
|
||||
return ((IComparable)(x)).CompareTo(y) == 0;
|
||||
}
|
||||
|
||||
#region ToDictionary
|
||||
/// <summary>
|
||||
/// 将实体指定的字段写入字典
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static Dictionary<string, object> ToDictionary<T>(this T t, Expression<Func<T, object>> expression) where T : class
|
||||
{
|
||||
Dictionary<string, object> dic = new Dictionary<string, object>();
|
||||
string[] fields = expression.GetExpressionToArray();
|
||||
PropertyInfo[] properties = expression == null ? t.GetType().GetProperties() : t.GetType().GetProperties().Where(x => fields.Contains(x.Name)).ToArray();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var value = property.GetValue(t, null);
|
||||
dic.Add(property.Name, value != null ? value.ToString() : "");
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> ToDictionary<TInterface, T>(this TInterface t, Dictionary<string, string> dic = null) where T : class, TInterface
|
||||
{
|
||||
if (dic == null)
|
||||
dic = new Dictionary<string, string>();
|
||||
var properties = typeof(T).GetProperties();
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var value = property.GetValue(t, null);
|
||||
if (value == null) continue;
|
||||
dic.Add(property.Name, value != null ? value.ToString() : "");
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static DataTable ToDataTable<T>(this IEnumerable<T> source, Expression<Func<T, object>> columns = null, bool contianKey = true)
|
||||
{
|
||||
DataTable dtReturn = new DataTable();
|
||||
if (source == null) return dtReturn;
|
||||
|
||||
PropertyInfo[] oProps = typeof(T).GetProperties()
|
||||
.Where(x => x.PropertyType.Name != "List`1").ToArray();
|
||||
if (columns != null)
|
||||
{
|
||||
string[] columnArray = columns.GetExpressionToArray();
|
||||
oProps = oProps.Where(x => columnArray.Contains(x.Name)).ToArray();
|
||||
}
|
||||
//移除自增主键
|
||||
PropertyInfo keyType = oProps.GetKeyProperty();// oProps.GetKeyProperty()?.PropertyType;
|
||||
if (!contianKey && keyType != null && (keyType.PropertyType == typeof(int) || keyType.PropertyType == typeof(long)))
|
||||
{
|
||||
oProps = oProps.Where(x => x.Name != keyType.Name).ToArray();
|
||||
}
|
||||
|
||||
foreach (var pi in oProps)
|
||||
{
|
||||
var colType = pi.PropertyType;
|
||||
|
||||
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
|
||||
{
|
||||
colType = colType.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
|
||||
}
|
||||
foreach (var rec in source)
|
||||
{
|
||||
var dr = dtReturn.NewRow();
|
||||
foreach (var pi in oProps)
|
||||
{
|
||||
dr[pi.Name] = pi.GetValue(rec, null) == null
|
||||
? DBNull.Value
|
||||
: pi.GetValue
|
||||
(rec, null);
|
||||
}
|
||||
dtReturn.Rows.Add(dr);
|
||||
}
|
||||
return dtReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,504 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Infrastructure.Const;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class LambdaExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> TakePage<T>(this IQueryable<T> queryable, int page, int size = 15)
|
||||
{
|
||||
return queryable.TakeOrderByPage<T>(page, size);
|
||||
}
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> TakeOrderByPage<T>(this IQueryable<T> queryable, int page, int size = 15, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBy = null)
|
||||
{
|
||||
if (page <= 0)
|
||||
{
|
||||
page = 1;
|
||||
}
|
||||
return Queryable.Take(Queryable.Skip(queryable.GetIQueryableOrderBy(orderBy.GetExpressionToDic()), (page - 1) * size), size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>true
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> True<T>()
|
||||
{
|
||||
return p => true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>false
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> False<T>()
|
||||
{
|
||||
|
||||
return p => false;
|
||||
}
|
||||
|
||||
public static ParameterExpression GetExpressionParameter(this Type type)
|
||||
{
|
||||
|
||||
return Expression.Parameter(type, "p");
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>p.propertyName
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="sort"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName)
|
||||
{
|
||||
return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter());
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建委托有返回值的表达式:p=>p.propertyName
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="sort"></param>
|
||||
/// <returns></returns>
|
||||
public static Func<T, TKey> GetFun<T, TKey>(this string propertyName)
|
||||
{
|
||||
return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter()).Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>false
|
||||
/// 在已知TKey字段类型时,如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID
|
||||
/// Expression<Func<Out_Scheduling, DateTime>> expression = x => x.CreateDate;指定了类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName, ParameterExpression parameter)
|
||||
{
|
||||
if (typeof(TKey).Name == "Object")
|
||||
return Expression.Lambda<Func<T, TKey>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter);
|
||||
return Expression.Lambda<Func<T, TKey>>(Expression.Property(parameter, propertyName), parameter);
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>false
|
||||
/// object不能确认字段类型(datetime,int,string),如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID
|
||||
/// Expression<Func<Out_Scheduling, object>> expression = x => x.CreateDate;任意类型的字段
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, object>> GetExpression<T>(this string propertyName)
|
||||
{
|
||||
return propertyName.GetExpression<T, object>(typeof(T).GetExpressionParameter());
|
||||
}
|
||||
|
||||
public static Expression<Func<T, object>> GetExpression<T>(this string propertyName, ParameterExpression parameter)
|
||||
{
|
||||
return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="propertyName">字段名</param>
|
||||
/// <param name="propertyValue">表达式的值</param>
|
||||
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
|
||||
/// p=>p.propertyName.Contains(propertyValue)</param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> CreateExpression<T>(this string propertyName, object propertyValue, LinqExpressionType expressionType)
|
||||
{
|
||||
return propertyName.CreateExpression<T>(propertyValue, null, expressionType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="propertyName">字段名</param>
|
||||
/// <param name="propertyValue">表达式的值</param>
|
||||
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
|
||||
/// p=>p.propertyName.Contains(propertyValue)</param>
|
||||
/// <returns></returns>
|
||||
private static Expression<Func<T, bool>> CreateExpression<T>(
|
||||
this string propertyName,
|
||||
object propertyValue,
|
||||
ParameterExpression parameter,
|
||||
LinqExpressionType expressionType)
|
||||
{
|
||||
Type proType = typeof(T).GetProperty(propertyName).PropertyType;
|
||||
//创建节点变量如p=>的节点p
|
||||
// parameter ??= Expression.Parameter(typeof(T), "p");//创建参数p
|
||||
parameter = parameter ?? Expression.Parameter(typeof(T), "p");
|
||||
|
||||
//创建节点的属性p=>p.name 属性name
|
||||
MemberExpression memberProperty = Expression.PropertyOrField(parameter, propertyName);
|
||||
if (expressionType == LinqExpressionType.In)
|
||||
{
|
||||
if (!(propertyValue is System.Collections.IList list) || list.Count == 0) throw new Exception("属性值类型不正确");
|
||||
|
||||
bool isStringValue = true;
|
||||
List<object> objList = new List<object>();
|
||||
|
||||
if (proType.ToString() != "System.String")
|
||||
{
|
||||
isStringValue = false;
|
||||
foreach (var value in list)
|
||||
{
|
||||
objList.Add(value.ToString().ChangeType(proType));
|
||||
}
|
||||
list = objList;
|
||||
}
|
||||
|
||||
if (isStringValue)
|
||||
{
|
||||
//string 类型的字段,如果值带有'单引号,EF会默认变成''两个单引号
|
||||
MethodInfo method = typeof(System.Collections.IList).GetMethod("Contains");
|
||||
//创建集合常量并设置为常量的值
|
||||
ConstantExpression constantCollection = Expression.Constant(list);
|
||||
//创建一个表示调用带参数的方法的:new string[]{"1","a"}.Contains("a");
|
||||
MethodCallExpression methodCall = Expression.Call(constantCollection, method, memberProperty);
|
||||
return Expression.Lambda<Func<T, bool>>(methodCall, parameter);
|
||||
}
|
||||
//非string字段,按上面方式处理报异常Null TypeMapping in Sql Tree
|
||||
BinaryExpression body = null;
|
||||
foreach (var value in list)
|
||||
{
|
||||
ConstantExpression constantExpression = Expression.Constant(value);
|
||||
UnaryExpression unaryExpression = Expression.Convert(memberProperty, constantExpression.Type);
|
||||
|
||||
body = body == null
|
||||
? Expression.Equal(unaryExpression, constantExpression)
|
||||
: Expression.OrElse(body, Expression.Equal(unaryExpression, constantExpression));
|
||||
}
|
||||
return Expression.Lambda<Func<T, bool>>(body, parameter);
|
||||
}
|
||||
|
||||
// object value = propertyValue;
|
||||
ConstantExpression constant = proType.ToString() == "System.String"
|
||||
? Expression.Constant(propertyValue) : Expression.Constant(propertyValue.ToString().ChangeType(proType));
|
||||
|
||||
UnaryExpression member = Expression.Convert(memberProperty, constant.Type);
|
||||
Expression<Func<T, bool>> expression;
|
||||
switch (expressionType)
|
||||
{
|
||||
//p=>p.propertyName == propertyValue
|
||||
case LinqExpressionType.Equal:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
|
||||
break;
|
||||
//p=>p.propertyName != propertyValue
|
||||
case LinqExpressionType.NotEqual:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName > propertyValue
|
||||
case LinqExpressionType.GreaterThan:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName < propertyValue
|
||||
case LinqExpressionType.LessThan:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName >= propertyValue
|
||||
case LinqExpressionType.ThanOrEqual:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName <= propertyValue
|
||||
case LinqExpressionType.LessThanOrEqual:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName.Contains(propertyValue)
|
||||
// p => !p.propertyName.Contains(propertyValue)
|
||||
case LinqExpressionType.Contains:
|
||||
case LinqExpressionType.NotContains:
|
||||
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
|
||||
constant = Expression.Constant(propertyValue, typeof(string));
|
||||
if (expressionType == LinqExpressionType.Contains)
|
||||
{
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.Call(member, method, constant), parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(member, method, constant)), parameter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// p => p.false
|
||||
expression = False<T>();
|
||||
break;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式转换成KeyValList(主要用于多字段排序,并且多个字段的排序规则不一样)
|
||||
/// 如有多个字段进行排序,参数格式为
|
||||
/// Expression<Func<Out_Scheduling, Dictionary<object, bool>>> orderBy = x => new Dictionary<object, bool>() {
|
||||
/// { x.ID, true },
|
||||
/// { x.DestWarehouseName, true }
|
||||
/// };
|
||||
/// 返回的是new Dictionary<object, bool>(){{}}key为排序字段,bool为升降序
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KeyValuePair<string, QueryOrderBy>> GetExpressionToPair<T>(this Expression<Func<T, Dictionary<object, QueryOrderBy>>> expression)
|
||||
{
|
||||
|
||||
foreach (var exp in ((ListInitExpression)expression.Body).Initializers)
|
||||
{
|
||||
yield return new KeyValuePair<string, QueryOrderBy>(
|
||||
exp.Arguments[0] is MemberExpression ?
|
||||
(exp.Arguments[0] as MemberExpression).Member.Name.ToString()
|
||||
: ((exp.Arguments[0] as UnaryExpression).Operand as MemberExpression).Member.Name,
|
||||
(QueryOrderBy)((exp.Arguments[1] as ConstantExpression).Value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式转换成KeyValList(主要用于多字段排序,并且多个字段的排序规则不一样)
|
||||
/// 如有多个字段进行排序,参数格式为
|
||||
/// Expression<Func<Out_Scheduling, Dictionary<object, QueryOrderBy>>> orderBy = x => new Dictionary<object, QueryOrderBy>() {
|
||||
/// { x.ID, QueryOrderBy.Desc },
|
||||
/// { x.DestWarehouseName, QueryOrderBy.Asc }
|
||||
/// };
|
||||
/// 返回的是new Dictionary<object, QueryOrderBy>(){{}}key为排序字段,QueryOrderBy为排序方式
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, QueryOrderBy> GetExpressionToDic<T>(this Expression<Func<T, Dictionary<object, QueryOrderBy>>> expression)
|
||||
{
|
||||
return expression.GetExpressionToPair().Reverse().ToList().ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 解析多字段排序
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="orderBySelector">string=排序的字段,bool=true降序/false升序</param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<TEntity> GetIQueryableOrderBy<TEntity>(this IQueryable<TEntity> queryable, Dictionary<string, QueryOrderBy> orderBySelector)
|
||||
{
|
||||
string[] orderByKeys = orderBySelector.Select(x => x.Key).ToArray();
|
||||
if (orderByKeys == null || orderByKeys.Length == 0) return queryable;
|
||||
|
||||
IOrderedQueryable<TEntity> queryableOrderBy = null;
|
||||
// string orderByKey = orderByKeys[^1];
|
||||
string orderByKey = orderByKeys[orderByKeys.Length-1];
|
||||
queryableOrderBy = orderBySelector[orderByKey] == QueryOrderBy.Desc
|
||||
? queryableOrderBy = queryable.OrderByDescending(orderByKey.GetExpression<TEntity>())
|
||||
: queryable.OrderBy(orderByKey.GetExpression<TEntity>());
|
||||
|
||||
for (int i = orderByKeys.Length - 2; i >= 0; i--)
|
||||
{
|
||||
queryableOrderBy = orderBySelector[orderByKeys[i]] == QueryOrderBy.Desc
|
||||
? queryableOrderBy.ThenByDescending(orderByKeys[i].GetExpression<TEntity>())
|
||||
: queryableOrderBy.ThenBy(orderByKeys[i].GetExpression<TEntity>());
|
||||
}
|
||||
return queryableOrderBy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象表达式指定属性的值
|
||||
/// 如获取:Out_Scheduling对象的ID或基他字段
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="expression">格式 Expression<Func<Out_Scheduling, object>>sch=x=>new {x.v1,x.v2} or x=>x.v1 解析里面的值返回为数组</param>
|
||||
/// <returns></returns>
|
||||
public static string[] GetExpressionToArray<TEntity>(this Expression<Func<TEntity, object>> expression)
|
||||
{
|
||||
string[] propertyNames = null;
|
||||
if (expression.Body is MemberExpression)
|
||||
{
|
||||
propertyNames = new string[] { ((MemberExpression)expression.Body).Member.Name };
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyNames = expression.GetExpressionProperty().Distinct().ToArray();
|
||||
}
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 与下面and生成方式有所不同,如果直接用表达式1.2进行合并产会提示数据源不同的异常,只能使用下面的的and合并
|
||||
/// 此种合并是在使用的同一个数据源(变量),生成的sql语句同样有性能问题(本身可以索引扫描的,生成的sql语句的case when变成索引查找)
|
||||
/// <summary>
|
||||
/// 通过字段动态生成where and /or表达
|
||||
/// 如:有多个where条件,当条件成立时where 1=1 and/or 2=2,依次往后拼接
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="listParas">ExpressionParameters
|
||||
/// 1、Field生成的字段
|
||||
/// 2、ExpressionType 表达式类型大于、小于、于大=、小于=、contains
|
||||
/// 3、Value表达式的值
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> And<T>(List<ExpressionParameters> listExpress)
|
||||
{
|
||||
return listExpress.Compose<T>(Expression.And);
|
||||
}
|
||||
/// <summary>
|
||||
/// 同上面and用法相同
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="listExpress"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> Or<T>(this List<ExpressionParameters> listExpress)
|
||||
{
|
||||
return listExpress.Compose<T>(Expression.Or);
|
||||
}
|
||||
private static Expression<Func<T, bool>> Compose<T>(this List<ExpressionParameters> listExpress, Func<Expression, Expression, Expression> merge)
|
||||
{
|
||||
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
|
||||
Expression<Func<T, bool>> expression = null;
|
||||
foreach (ExpressionParameters exp in listExpress)
|
||||
{
|
||||
if (expression == null)
|
||||
{
|
||||
expression = exp.Field.GetExpression<T, bool>(parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
expression = expression.Compose(exp.Field.GetExpression<T, bool>(parameter), merge);
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
/// <summary>
|
||||
/// https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
|
||||
/// 表达式合并(合并生产的sql语句有性能问题)
|
||||
/// 合并两个where条件,如:多个查询条件时,判断条件成立才where
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="first"></param>
|
||||
/// <param name="second"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
||||
{
|
||||
return first.Compose(second, Expression.And);
|
||||
}
|
||||
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
||||
{
|
||||
return first.Compose(second, Expression.Or);
|
||||
}
|
||||
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
|
||||
{
|
||||
// build parameter map (from parameters of second to parameters of first)
|
||||
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
|
||||
// replace parameters in the second lambda expression with parameters from the first
|
||||
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
|
||||
// apply composition of lambda expression bodies to parameters from the first expression
|
||||
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
|
||||
}
|
||||
|
||||
public static IQueryable<Result> GetQueryableSelect<Source, Result>(this IQueryable<Source> queryable)
|
||||
{
|
||||
Expression<Func<Source, Result>> expression = CreateMemberInitExpression<Source, Result>();
|
||||
return queryable.Select(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态创建表达式Expression<Func<Animal, User>> expression = CreateMemberInitExpression<Animal, User>();
|
||||
///结果为Expression<Func<Animal, User>> expression1 = x => new User() { Age = x.Age, Species = x.Species };
|
||||
///参照文档https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.memberinitexpression?redirectedfrom=MSDN&view=netframework-4.8
|
||||
/// </summary>
|
||||
/// <typeparam name="Source"></typeparam>
|
||||
/// <typeparam name="Result"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<Source, Result>> CreateMemberInitExpression<Source, Result>(Type resultType = null)
|
||||
{
|
||||
resultType = resultType ?? typeof(Result);
|
||||
ParameterExpression left = Expression.Parameter(typeof(Source), "p");
|
||||
NewExpression newExpression = Expression.New(resultType);
|
||||
PropertyInfo[] propertyInfos = resultType.GetProperties();
|
||||
List<MemberBinding> memberBindings = new List<MemberBinding>();
|
||||
foreach (PropertyInfo propertyInfo in propertyInfos)
|
||||
{
|
||||
MemberExpression member = Expression.Property(left, propertyInfo.Name);
|
||||
MemberBinding speciesMemberBinding = Expression.Bind(resultType.GetMember(propertyInfo.Name)[0], member);
|
||||
memberBindings.Add(speciesMemberBinding);
|
||||
}
|
||||
MemberInitExpression memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
|
||||
Expression<Func<Source, Result>> expression = Expression.Lambda<Func<Source, Result>>(memberInitExpression, new ParameterExpression[] { left });
|
||||
return expression;
|
||||
}
|
||||
public static Expression<Func<Source, object>> CreateMemberInitExpression<Source>(Type resultType)
|
||||
{
|
||||
return CreateMemberInitExpression<Source, object>(resultType);
|
||||
}
|
||||
/// <summary>
|
||||
/// 属性判断待完
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyInfo> GetGenericProperties(this Type type)
|
||||
{
|
||||
return type.GetProperties().GetGenericProperties();
|
||||
}
|
||||
/// <summary>
|
||||
/// 属性判断待完
|
||||
/// </summary>
|
||||
/// <param name="properties"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyInfo> GetGenericProperties(this IEnumerable<PropertyInfo> properties)
|
||||
{
|
||||
return properties.Where(x => !x.PropertyType.IsGenericType && x.PropertyType.GetInterface("IList") == null || x.PropertyType.GetInterface("IEnumerable", false) == null);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpressionParameters
|
||||
{
|
||||
public string Field { get; set; }
|
||||
public LinqExpressionType ExpressionType { get; set; }
|
||||
public object Value { get; set; }
|
||||
// public
|
||||
}
|
||||
public class ParameterRebinder : ExpressionVisitor
|
||||
{
|
||||
|
||||
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
|
||||
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
|
||||
{
|
||||
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
|
||||
}
|
||||
|
||||
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
|
||||
{
|
||||
return new ParameterRebinder(map).Visit(exp);
|
||||
}
|
||||
protected override Expression VisitParameter(ParameterExpression p)
|
||||
{
|
||||
ParameterExpression replacement;
|
||||
if (map.TryGetValue(p, out replacement))
|
||||
{
|
||||
p = replacement;
|
||||
}
|
||||
return base.VisitParameter(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class SecurityEncDecryptExtensions
|
||||
{
|
||||
private static byte[] Keys = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
|
||||
/// <summary>
|
||||
/// DES加密字符串
|
||||
/// </summary>
|
||||
/// <param name="encryptString">待加密的字符串</param>
|
||||
/// <param name="encryptKey">加密密钥,要求为16位</param>
|
||||
/// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
|
||||
|
||||
public static string EncryptDES(this string encryptString, string encryptKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 16));
|
||||
byte[] rgbIV = Keys;
|
||||
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
|
||||
|
||||
using (var DCSP = DES.Create())
|
||||
{
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
|
||||
{
|
||||
cStream.Write(inputByteArray, 0, inputByteArray.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return Convert.ToBase64String(mStream.ToArray()).Replace('+', '_').Replace('/', '~');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("密码加密异常" + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DES解密字符串
|
||||
/// </summary>
|
||||
/// <param name="decryptString">待解密的字符串</param>
|
||||
/// <param name="decryptKey">解密密钥,要求为16位,和加密密钥相同</param>
|
||||
/// <returns>解密成功返回解密后的字符串,失败返源串</returns>
|
||||
|
||||
public static string DecryptDES(this string decryptString, string decryptKey)
|
||||
{
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 16));
|
||||
byte[] rgbIV = Keys;
|
||||
byte[] inputByteArray = Convert.FromBase64String(decryptString.Replace('_', '+').Replace('~', '/'));
|
||||
using (var DCSP = DES.Create())
|
||||
{
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
|
||||
{
|
||||
byte[] inputByteArrays = new byte[inputByteArray.Length];
|
||||
cStream.Write(inputByteArray, 0, inputByteArray.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return Encoding.UTF8.GetString(mStream.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryDecryptDES(this string decryptString, string decryptKey, out string result)
|
||||
{
|
||||
result = "";
|
||||
try
|
||||
{
|
||||
result = DecryptDES(decryptString, decryptKey);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using Infrastructure.Extensions.AutofacManager;
|
||||
using Infrastructure.Provider;
|
||||
|
||||
namespace Infrastructure.Extensions
|
||||
{
|
||||
public static class ServerExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回的路径后面不带/,拼接时需要自己加上/
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string MapPath(this string path)
|
||||
{
|
||||
return MapPath(path, false);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="rootPath">获取wwwroot路径</param>
|
||||
/// <returns></returns>
|
||||
public static string MapPath(this string path,bool rootPath)
|
||||
{
|
||||
return AutofacContainerModule.GetService<IPathProvider>().MapPath(path,rootPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,25 @@
|
|||
namespace Infrastructure
|
||||
{
|
||||
|
||||
public class Filter
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Contrast { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
public class FilterGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// or /and
|
||||
/// </summary>
|
||||
public string Operation { get; set; }
|
||||
public Filter[] Filters { get; set; }
|
||||
public FilterGroup[] Children { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : FairUtility
|
||||
// Author : Yubao Li
|
||||
// Created : 10-13-2015
|
||||
//
|
||||
// Last Modified By : Yubao Li
|
||||
// Last Modified On : 10-13-2015
|
||||
// ***********************************************************************
|
||||
// <copyright file="GenerateId.cs" company="">
|
||||
// Copyright (c) . All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>创建唯一ID</summary>
|
||||
// ***********************************************************************
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public class GenerateId
|
||||
{
|
||||
public static string GetGuidHash()
|
||||
{
|
||||
return Guid.NewGuid().ToString().GetHashCode().ToString("x");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成一个长整型,可以转成19字节长的字符串
|
||||
/// </summary>
|
||||
/// <returns>System.Int64.</returns>
|
||||
public static long GenerateLong()
|
||||
{
|
||||
byte[] buffer = Guid.NewGuid().ToByteArray();
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成16个字节长度的数据与英文组合串
|
||||
/// </summary>
|
||||
public static string GenerateStr()
|
||||
{
|
||||
long i = 1;
|
||||
|
||||
foreach (byte b in Guid.NewGuid().ToByteArray())
|
||||
{
|
||||
i *= ((int)b + 1);
|
||||
}
|
||||
|
||||
return String.Format("{0:x}", i - DateTime.Now.Ticks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建11位的英文与数字组合
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string ShortStr()
|
||||
{
|
||||
return Convert(GenerateLong());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 唯一订单号生成
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GenerateOrderNumber()
|
||||
{
|
||||
string strDateTimeNumber = DateTime.Now.ToString("yyyyMMddHHmmssffff");
|
||||
string strRandomResult = NextRandom(1000, 1).ToString("0000");
|
||||
|
||||
return strDateTimeNumber + strRandomResult;
|
||||
}
|
||||
|
||||
#region private
|
||||
|
||||
/// <summary>
|
||||
/// 参考:msdn上的RNGCryptoServiceProvider例子
|
||||
/// </summary>
|
||||
/// <param name="numSeeds"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private static int NextRandom(int numSeeds, int length)
|
||||
{
|
||||
// Create a byte array to hold the random value.
|
||||
byte[] randomNumber = new byte[length];
|
||||
// Create a new instance of the RNGCryptoServiceProvider.
|
||||
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
|
||||
// Fill the array with a random value.
|
||||
rng.GetBytes(randomNumber);
|
||||
// Convert the byte to an uint value to make the modulus operation easier.
|
||||
uint randomResult = 0x0;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
randomResult |= ((uint) randomNumber[i] << ((length - 1 - i)*8));
|
||||
}
|
||||
|
||||
return (int) (randomResult%numSeeds) + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static string Seq = "s9LFkgy5RovixI1aOf8UhdY3r4DMplQZJXPqebE0WSjBn7wVzmN2Gc6THCAKut";
|
||||
|
||||
/// <summary>
|
||||
/// 10进制转换为62进制
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
private static string Convert(long id)
|
||||
{
|
||||
if (id < 62)
|
||||
{
|
||||
return Seq[(int) id].ToString();
|
||||
}
|
||||
int y = (int) (id%62);
|
||||
long x = (long) (id/62);
|
||||
|
||||
return Convert(x) + Seq[y];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class AESHelper
|
||||
{
|
||||
//
|
||||
// 摘要:
|
||||
// 32位处理key
|
||||
//
|
||||
// 参数:
|
||||
// key:
|
||||
// 原字节
|
||||
private static string GetAesKey(string key)
|
||||
{
|
||||
int length = key.Length;
|
||||
if (length < 32)
|
||||
{
|
||||
for (int i = 0; i < 32 - length; i++)
|
||||
{
|
||||
key += "0";
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
return key[..32];
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 使用AES加密字符串
|
||||
//
|
||||
// 参数:
|
||||
// content:
|
||||
// 加密内容
|
||||
//
|
||||
// key:
|
||||
// 秘钥
|
||||
//
|
||||
// vi:
|
||||
// 偏移量
|
||||
//
|
||||
// 返回结果:
|
||||
// Base64字符串结果
|
||||
public static string AesEncrypt(string content, string key, string vi = "1234567890000000")
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(GetAesKey(key));
|
||||
byte[] bytes2 = Encoding.UTF8.GetBytes(vi);
|
||||
byte[] bytes3 = Encoding.UTF8.GetBytes(content);
|
||||
SymmetricAlgorithm symmetricAlgorithm = Aes.Create();
|
||||
symmetricAlgorithm.IV = bytes2;
|
||||
symmetricAlgorithm.Key = bytes;
|
||||
symmetricAlgorithm.Mode = CipherMode.CBC;
|
||||
symmetricAlgorithm.Padding = PaddingMode.PKCS7;
|
||||
ICryptoTransform cryptoTransform = symmetricAlgorithm.CreateEncryptor();
|
||||
byte[] inArray = cryptoTransform.TransformFinalBlock(bytes3, 0, bytes3.Length);
|
||||
return Convert.ToBase64String(inArray);
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 使用AES解密字符串
|
||||
//
|
||||
// 参数:
|
||||
// content:
|
||||
// 内容
|
||||
//
|
||||
// key:
|
||||
// 秘钥
|
||||
//
|
||||
// vi:
|
||||
// 偏移量
|
||||
//
|
||||
// 返回结果:
|
||||
// UTF8解密结果
|
||||
public static string AesDecrypt(string content, string key, string vi = "1234567890000000")
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(GetAesKey(key));
|
||||
byte[] bytes2 = Encoding.UTF8.GetBytes(vi);
|
||||
byte[] array = Convert.FromBase64String(content);
|
||||
SymmetricAlgorithm symmetricAlgorithm = Aes.Create();
|
||||
symmetricAlgorithm.IV = bytes2;
|
||||
symmetricAlgorithm.Key = bytes;
|
||||
symmetricAlgorithm.Mode = CipherMode.CBC;
|
||||
symmetricAlgorithm.Padding = PaddingMode.PKCS7;
|
||||
ICryptoTransform cryptoTransform = symmetricAlgorithm.CreateDecryptor();
|
||||
byte[] bytes3 = cryptoTransform.TransformFinalBlock(array, 0, array.Length);
|
||||
return Encoding.UTF8.GetString(bytes3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 常用公共类
|
||||
/// </summary>
|
||||
public class CommonHelper
|
||||
{
|
||||
#region Stopwatch计时器
|
||||
/// <summary>
|
||||
/// 计时器开始
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Stopwatch TimerStart()
|
||||
{
|
||||
Stopwatch watch = new Stopwatch();
|
||||
watch.Reset();
|
||||
watch.Start();
|
||||
return watch;
|
||||
}
|
||||
/// <summary>
|
||||
/// 计时器结束
|
||||
/// </summary>
|
||||
/// <param name="watch"></param>
|
||||
/// <returns></returns>
|
||||
public static string TimerEnd(Stopwatch watch)
|
||||
{
|
||||
watch.Stop();
|
||||
double costtime = watch.ElapsedMilliseconds;
|
||||
return costtime.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 删除数组中的重复项
|
||||
/// <summary>
|
||||
/// 删除数组中的重复项
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
/// <returns></returns>
|
||||
public static string[] RemoveDup(string[] values)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
for (int i = 0; i < values.Length; i++)//遍历数组成员
|
||||
{
|
||||
if (!list.Contains(values[i]))
|
||||
{
|
||||
list.Add(values[i]);
|
||||
};
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 自动生成日期编号
|
||||
/// <summary>
|
||||
/// 自动生成编号 201008251145409865
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string CreateNo()
|
||||
{
|
||||
Random random = new Random();
|
||||
string strRandom = random.Next(1000, 10000).ToString(); //生成编号
|
||||
string code = DateTime.Now.ToString("yyyyMMddHHmmss") + strRandom;//形如
|
||||
return code;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 生成0-9随机数
|
||||
/// <summary>
|
||||
/// 生成0-9随机数
|
||||
/// </summary>
|
||||
/// <param name="codeNum">生成长度</param>
|
||||
/// <returns></returns>
|
||||
public static string RndNum(int codeNum)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(codeNum);
|
||||
Random rand = new Random();
|
||||
for (int i = 1; i < codeNum + 1; i++)
|
||||
{
|
||||
int t = rand.Next(9);
|
||||
sb.AppendFormat("{0}", t);
|
||||
}
|
||||
return sb.ToString();
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 删除最后一个字符之后的字符
|
||||
/// <summary>
|
||||
/// 删除最后结尾的一个逗号
|
||||
/// </summary>
|
||||
public static string DelLastComma(string str)
|
||||
{
|
||||
return str.Substring(0, str.LastIndexOf(","));
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除最后结尾的指定字符后的字符
|
||||
/// </summary>
|
||||
public static string DelLastChar(string str, string strchar)
|
||||
{
|
||||
return str.Substring(0, str.LastIndexOf(strchar));
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除最后结尾的长度
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="Length"></param>
|
||||
/// <returns></returns>
|
||||
public static string DelLastLength(string str, int Length)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return "";
|
||||
str = str.Substring(0, str.Length - Length);
|
||||
return str;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using Enyim.Caching.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class ConfigHelper
|
||||
{
|
||||
public static IConfigurationRoot GetConfigRoot()
|
||||
{
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.SetBasePath(System.IO.Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||
.AddJsonFile(
|
||||
$"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"}.json",
|
||||
optional: true)
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
var configuration = configurationBuilder.Build();
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class DateTimeHelper
|
||||
{
|
||||
public static string FriendlyDate(DateTime? date)
|
||||
{
|
||||
if (!date.HasValue) return string.Empty;
|
||||
|
||||
string strDate = date.Value.ToString("yyyy-MM-dd");
|
||||
string vDate = string.Empty;
|
||||
if(DateTime.Now.ToString("yyyy-MM-dd")==strDate)
|
||||
{
|
||||
vDate = "今天";
|
||||
}
|
||||
else if (DateTime.Now.AddDays(1).ToString("yyyy-MM-dd") == strDate)
|
||||
{
|
||||
vDate = "明天";
|
||||
}
|
||||
else if (DateTime.Now.AddDays(2).ToString("yyyy-MM-dd") == strDate)
|
||||
{
|
||||
vDate = "后天";
|
||||
}
|
||||
else if (DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") == strDate)
|
||||
{
|
||||
vDate = "昨天";
|
||||
}
|
||||
else if (DateTime.Now.AddDays(2).ToString("yyyy-MM-dd") == strDate)
|
||||
{
|
||||
vDate = "前天";
|
||||
}
|
||||
else
|
||||
{
|
||||
vDate = strDate;
|
||||
}
|
||||
|
||||
return vDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
using Infrastructure.Helpers.Excel.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Helpers.Excel
|
||||
{
|
||||
public class ExcelConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
/// <summary>
|
||||
/// 前景色
|
||||
/// </summary>
|
||||
public System.Drawing.Color ForeColor { get; set; }
|
||||
/// <summary>
|
||||
/// 背景色
|
||||
/// </summary>
|
||||
public System.Drawing.Color Background { get; set; }
|
||||
private short _titlepoint;
|
||||
/// <summary>
|
||||
/// 标题字号
|
||||
/// </summary>
|
||||
public short TitlePoint
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_titlepoint == 0)
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _titlepoint;
|
||||
}
|
||||
}
|
||||
set { _titlepoint = value; }
|
||||
}
|
||||
private short _headpoint;
|
||||
/// <summary>
|
||||
/// 列头字号
|
||||
/// </summary>
|
||||
public short HeadPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_headpoint == 0)
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _headpoint;
|
||||
}
|
||||
}
|
||||
set { _headpoint = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 标题高度
|
||||
/// </summary>
|
||||
public short TitleHeight { get; set; }
|
||||
/// <summary>
|
||||
/// 列标题高度
|
||||
/// </summary>
|
||||
public short HeadHeight { get; set; }
|
||||
private string _titlefont;
|
||||
/// <summary>
|
||||
/// 标题字体
|
||||
/// </summary>
|
||||
public string TitleFont
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_titlefont == null)
|
||||
{
|
||||
return "微软雅黑";
|
||||
}
|
||||
else
|
||||
{
|
||||
return _titlefont;
|
||||
}
|
||||
}
|
||||
set { _titlefont = value; }
|
||||
}
|
||||
private string _headfont;
|
||||
/// <summary>
|
||||
/// 列头字体
|
||||
/// </summary>
|
||||
public string HeadFont
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_headfont == null)
|
||||
{
|
||||
return "微软雅黑";
|
||||
}
|
||||
else
|
||||
{
|
||||
return _headfont;
|
||||
}
|
||||
}
|
||||
set { _headfont = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否按内容长度来适应表格宽度
|
||||
/// </summary>
|
||||
public bool IsAllSizeColumn { get; set; }
|
||||
/// <summary>
|
||||
/// 列设置
|
||||
/// </summary>
|
||||
public List<ColumnModel> ColumnEntity { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,505 @@
|
|||
using NPOI.HPSF;
|
||||
using NPOI.HSSF.UserModel;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Helpers.Excel
|
||||
{
|
||||
public class ExcelHelper
|
||||
{
|
||||
#region DataTable导出到Excel的MemoryStream
|
||||
/// <summary>
|
||||
/// DataTable导出到Excel的MemoryStream Export()
|
||||
/// </summary>
|
||||
/// <param name="dtSource">DataTable数据源</param>
|
||||
/// <param name="excelConfig">导出设置包含文件名、标题、列设置</param>
|
||||
public static MemoryStream ExportMemoryStream(DataTable dtSource, ExcelConfig excelConfig)
|
||||
{
|
||||
Dictionary<string, DataColumn> DataColumnMap = new Dictionary<string, DataColumn>();
|
||||
|
||||
//DataTable dt = dtSource.Clone();
|
||||
//var columns = dt.Columns;
|
||||
foreach (DataColumn column in dtSource.Columns)
|
||||
{
|
||||
bool v = excelConfig.ColumnEntity.Exists(t => t.Column == column.ColumnName);
|
||||
if (v)
|
||||
{
|
||||
DataColumnMap.Add(column.ColumnName, column);
|
||||
//dtSource.Columns.Remove(column.ColumnName);
|
||||
}
|
||||
/*else {
|
||||
DataColumnMap.Add(column.ColumnName, column);
|
||||
}*/
|
||||
}
|
||||
|
||||
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||
ISheet sheet = workbook.CreateSheet();
|
||||
#region 右击文件 属性信息
|
||||
{
|
||||
DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
|
||||
dsi.Company = "山东慧创信息科技有限公司";
|
||||
workbook.DocumentSummaryInformation = dsi;
|
||||
|
||||
SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
|
||||
si.Title = "标题信息"; //填加xls文件标题信息
|
||||
si.Subject = "主题信息";//填加文件主题信息
|
||||
si.CreateDateTime = System.DateTime.Now;
|
||||
workbook.SummaryInformation = si;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设置标题样式
|
||||
ICellStyle headStyle = workbook.CreateCellStyle();
|
||||
int[] arrColWidth = new int[excelConfig.ColumnEntity.Count];
|
||||
string[] arrColName = new string[excelConfig.ColumnEntity.Count];//列名
|
||||
ICellStyle[] arryColumStyle = new ICellStyle[excelConfig.ColumnEntity.Count];//样式表
|
||||
headStyle.Alignment = HorizontalAlignment.Center; // ------------------
|
||||
if (excelConfig.Background != new System.Drawing.Color())
|
||||
{
|
||||
if (excelConfig.Background != new System.Drawing.Color())
|
||||
{
|
||||
headStyle.FillPattern = FillPattern.SolidForeground;
|
||||
headStyle.FillForegroundColor = GetXLColour(workbook, excelConfig.Background);
|
||||
}
|
||||
}
|
||||
IFont font = workbook.CreateFont();
|
||||
font.FontHeightInPoints = excelConfig.TitlePoint;
|
||||
if (excelConfig.ForeColor != new System.Drawing.Color())
|
||||
{
|
||||
font.Color = GetXLColour(workbook, excelConfig.ForeColor);
|
||||
}
|
||||
font.IsBold = true;
|
||||
headStyle.SetFont(font);
|
||||
#endregion
|
||||
|
||||
#region 列头及样式
|
||||
ICellStyle cHeadStyle = workbook.CreateCellStyle();
|
||||
cHeadStyle.Alignment = HorizontalAlignment.Center; // ------------------
|
||||
IFont cfont = workbook.CreateFont();
|
||||
cfont.FontHeightInPoints = excelConfig.HeadPoint;
|
||||
cHeadStyle.SetFont(cfont);
|
||||
#endregion
|
||||
|
||||
#region 设置内容单元格样式
|
||||
int colNum = 0;
|
||||
foreach (var columnentity in excelConfig.ColumnEntity)
|
||||
{
|
||||
//DataColumn item = DataColumnMap[column.Column];
|
||||
|
||||
|
||||
|
||||
ICellStyle columnStyle = workbook.CreateCellStyle();
|
||||
columnStyle.Alignment = HorizontalAlignment.Center;
|
||||
//Encoding.GetEncoding(936)
|
||||
arrColWidth[colNum] = Encoding.UTF8.GetBytes(columnentity.Column).Length;
|
||||
arrColName[colNum] = columnentity.Column.ToString();
|
||||
arrColName[colNum] = columnentity.ExcelColumn;
|
||||
if (columnentity.Width != 0)
|
||||
{
|
||||
arrColWidth[colNum] = columnentity.Width;
|
||||
}
|
||||
if (columnentity.Background != new System.Drawing.Color())
|
||||
{
|
||||
if (columnentity.Background != new System.Drawing.Color())
|
||||
{
|
||||
columnStyle.FillPattern = FillPattern.SolidForeground;
|
||||
columnStyle.FillForegroundColor = GetXLColour(workbook, columnentity.Background);
|
||||
}
|
||||
}
|
||||
if (columnentity.Font != null || columnentity.Point != 0 || columnentity.ForeColor != new System.Drawing.Color())
|
||||
{
|
||||
IFont columnFont = workbook.CreateFont();
|
||||
columnFont.FontHeightInPoints = 10;
|
||||
if (columnentity.Font != null)
|
||||
{
|
||||
columnFont.FontName = columnentity.Font;
|
||||
}
|
||||
if (columnentity.Point != 0)
|
||||
{
|
||||
columnFont.FontHeightInPoints = columnentity.Point;
|
||||
}
|
||||
if (columnentity.ForeColor != new System.Drawing.Color())
|
||||
{
|
||||
columnFont.Color = GetXLColour(workbook, columnentity.ForeColor);
|
||||
}
|
||||
columnStyle.SetFont(font);
|
||||
}
|
||||
columnStyle.Alignment = getAlignment(columnentity.Alignment);
|
||||
arryColumStyle[colNum] = columnStyle;
|
||||
|
||||
colNum++;
|
||||
}
|
||||
if (excelConfig.IsAllSizeColumn)
|
||||
{
|
||||
#region 根据列中最长列的长度取得列宽
|
||||
for (int i = 0; i < dtSource.Rows.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < excelConfig.ColumnEntity.Count; j++)
|
||||
{
|
||||
if (arrColWidth[j] != 0)
|
||||
{
|
||||
//Encoding.GetEncoding(936)
|
||||
int intTemp = Encoding.UTF8.GetBytes(dtSource.Rows[i][excelConfig.ColumnEntity[j].Column].ToString()).Length;
|
||||
if (intTemp > arrColWidth[j])
|
||||
{
|
||||
arrColWidth[j] = intTemp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
int rowIndex = 0;
|
||||
|
||||
#region 表头及样式
|
||||
if (excelConfig.Title != null)
|
||||
{
|
||||
IRow headerRow = sheet.CreateRow(rowIndex);
|
||||
rowIndex++;
|
||||
if (excelConfig.TitleHeight != 0)
|
||||
{
|
||||
headerRow.Height = (short)(excelConfig.TitleHeight * 20);
|
||||
}
|
||||
headerRow.HeightInPoints = 25;
|
||||
headerRow.CreateCell(0).SetCellValue(excelConfig.Title);
|
||||
headerRow.GetCell(0).CellStyle = headStyle;
|
||||
if (excelConfig.ColumnEntity.Count > 1)
|
||||
{
|
||||
sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, excelConfig.ColumnEntity.Count - 1)); // ------------------
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 列头及样式
|
||||
{
|
||||
IRow headerRow = sheet.CreateRow(rowIndex);
|
||||
rowIndex++;
|
||||
colNum = 0;
|
||||
#region 如果设置了列标题就按列标题定义列头,没定义直接按字段名输出
|
||||
foreach (var column in excelConfig.ColumnEntity)
|
||||
{
|
||||
headerRow.CreateCell(colNum).SetCellValue(arrColName[colNum]);
|
||||
headerRow.GetCell(colNum).CellStyle = cHeadStyle;
|
||||
//设置列宽
|
||||
//sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);
|
||||
|
||||
int colWidth = (arrColWidth[colNum] + 1) * 256;
|
||||
if (colWidth < 255 * 256)
|
||||
{
|
||||
sheet.SetColumnWidth(colNum, colWidth < 3000 ? 3000 : colWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
sheet.SetColumnWidth(colNum, 6000);
|
||||
}
|
||||
colNum++;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
ICellStyle dateStyle = workbook.CreateCellStyle();
|
||||
IDataFormat format = workbook.CreateDataFormat();
|
||||
dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");
|
||||
Dictionary<string, ICellStyle> dateStyleMap = new Dictionary<string, ICellStyle>();
|
||||
dateStyleMap.Add("yyyy-mm-dd", dateStyle);
|
||||
|
||||
|
||||
|
||||
|
||||
foreach (DataRow row in dtSource.Rows)
|
||||
{
|
||||
#region 新建表,填充表头,填充列头,样式
|
||||
if (rowIndex == 65535)
|
||||
{
|
||||
sheet = workbook.CreateSheet();
|
||||
rowIndex = 0;
|
||||
#region 表头及样式
|
||||
{
|
||||
if (excelConfig.Title != null)
|
||||
{
|
||||
IRow headerRow = sheet.CreateRow(rowIndex);
|
||||
rowIndex++;
|
||||
if (excelConfig.TitleHeight != 0)
|
||||
{
|
||||
headerRow.Height = (short)(excelConfig.TitleHeight * 20);
|
||||
}
|
||||
headerRow.HeightInPoints = 25;
|
||||
headerRow.CreateCell(0).SetCellValue(excelConfig.Title);
|
||||
headerRow.GetCell(0).CellStyle = headStyle;
|
||||
sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, excelConfig.ColumnEntity.Count - 1)); // ------------------
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 列头及样式
|
||||
{
|
||||
IRow headerRow = sheet.CreateRow(rowIndex);
|
||||
rowIndex++;
|
||||
#region 如果设置了列标题就按列标题定义列头,没定义直接按字段名输出
|
||||
colNum = 0;
|
||||
foreach (var column in excelConfig.ColumnEntity)
|
||||
{
|
||||
headerRow.CreateCell(colNum).SetCellValue(arrColName[colNum]);
|
||||
headerRow.GetCell(colNum).CellStyle = cHeadStyle;
|
||||
//设置列宽
|
||||
sheet.SetColumnWidth(colNum, (arrColWidth[colNum] + 1) * 256);
|
||||
colNum++;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 填充内容
|
||||
IRow dataRow = sheet.CreateRow(rowIndex);
|
||||
colNum = 0;
|
||||
foreach (var columnentity in excelConfig.ColumnEntity)
|
||||
{
|
||||
ICell newCell = dataRow.CreateCell(colNum);
|
||||
newCell.CellStyle = arryColumStyle[colNum];
|
||||
string drValue = row[columnentity.Column].ToString();
|
||||
|
||||
//ColumnModel columnentity = excelConfig.ColumnEntity.Find(t => t.Column == column.ColumnName);
|
||||
if (!string.IsNullOrEmpty(columnentity.DateFormat))
|
||||
{
|
||||
if (!dateStyleMap.ContainsKey(columnentity.DateFormat))
|
||||
{
|
||||
ICellStyle dateStyle2 = workbook.CreateCellStyle();
|
||||
IDataFormat format2 = workbook.CreateDataFormat();
|
||||
dateStyle2.DataFormat = format.GetFormat(columnentity.DateFormat);
|
||||
dateStyleMap.Add(columnentity.DateFormat, dateStyle2);
|
||||
}
|
||||
|
||||
|
||||
SetCell(newCell, dateStyleMap[columnentity.DateFormat], DataColumnMap[columnentity.Column].DataType, drValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
SetCell(newCell, dateStyle, DataColumnMap[columnentity.Column].DataType, drValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
colNum++;
|
||||
}
|
||||
#endregion
|
||||
rowIndex++;
|
||||
}
|
||||
MemoryStream ms = new MemoryStream();
|
||||
workbook.Write(ms);
|
||||
ms.Flush();
|
||||
ms.Position = 0;
|
||||
return ms;
|
||||
}
|
||||
#endregion
|
||||
#region 设置表格内容
|
||||
private static void SetCell(ICell newCell, ICellStyle dateStyle, Type dataType, string drValue)
|
||||
{
|
||||
switch (dataType.ToString())
|
||||
{
|
||||
case "System.String"://字符串类型
|
||||
newCell.SetCellValue(drValue);
|
||||
break;
|
||||
case "System.DateTime"://日期类型
|
||||
System.DateTime dateV;
|
||||
if (System.DateTime.TryParse(drValue, out dateV))
|
||||
{
|
||||
newCell.SetCellValue(dateV);
|
||||
}
|
||||
else
|
||||
{
|
||||
newCell.SetCellValue("");
|
||||
}
|
||||
newCell.CellStyle = dateStyle;//格式化显示
|
||||
break;
|
||||
case "System.Boolean"://布尔型
|
||||
bool boolV = false;
|
||||
bool.TryParse(drValue, out boolV);
|
||||
newCell.SetCellValue(boolV);
|
||||
break;
|
||||
case "System.Int16"://整型
|
||||
case "System.Int32":
|
||||
case "System.Int64":
|
||||
case "System.Byte":
|
||||
int intV = 0;
|
||||
int.TryParse(drValue, out intV);
|
||||
newCell.SetCellValue(intV);
|
||||
break;
|
||||
case "System.Decimal"://浮点型
|
||||
case "System.Double":
|
||||
double doubV = 0;
|
||||
double.TryParse(drValue, out doubV);
|
||||
newCell.SetCellValue(doubV);
|
||||
break;
|
||||
case "System.DBNull"://空值处理
|
||||
newCell.SetCellValue("");
|
||||
break;
|
||||
default:
|
||||
newCell.SetCellValue("");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 从Excel导入
|
||||
/// <summary>
|
||||
/// 读取excel ,默认第一行为标头
|
||||
/// </summary>
|
||||
/// <param name="strFileName">excel文档路径</param>
|
||||
/// <returns></returns>
|
||||
public static DataTable ExcelImport(string strFileName)
|
||||
{
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
ISheet sheet = null;
|
||||
using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
if (strFileName.IndexOf(".xlsx") == -1)//2003
|
||||
{
|
||||
HSSFWorkbook hssfworkbook = new HSSFWorkbook(file);
|
||||
sheet = hssfworkbook.GetSheetAt(0);
|
||||
}
|
||||
else//2007
|
||||
{
|
||||
XSSFWorkbook xssfworkbook = new XSSFWorkbook(file);
|
||||
sheet = xssfworkbook.GetSheetAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator rows = sheet.GetRowEnumerator();
|
||||
|
||||
IRow headerRow = sheet.GetRow(0);
|
||||
int cellCount = headerRow.LastCellNum;
|
||||
|
||||
for (int j = 0; j < cellCount; j++)
|
||||
{
|
||||
ICell cell = headerRow.GetCell(j);
|
||||
dt.Columns.Add(cell.ToString());
|
||||
}
|
||||
|
||||
for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
|
||||
{
|
||||
IRow row = sheet.GetRow(i);
|
||||
DataRow dataRow = dt.NewRow();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; j++)
|
||||
{
|
||||
if (row.GetCell(j) != null)
|
||||
dataRow[j] = row.GetCell(j).ToString();
|
||||
}
|
||||
|
||||
dt.Rows.Add(dataRow);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
/// <summary>
|
||||
/// 读取excel ,默认第一行为标头
|
||||
/// </summary>
|
||||
/// <param name="fileStream">文件数据流</param>
|
||||
/// <param name="flieType">文件类型</param>
|
||||
/// <returns></returns>
|
||||
public static DataTable ExcelImport(Stream fileStream, string flieType)
|
||||
{
|
||||
DataTable dt = new DataTable();
|
||||
ISheet sheet = null;
|
||||
if (flieType == ".xls")
|
||||
{
|
||||
HSSFWorkbook hssfworkbook = new HSSFWorkbook(fileStream);
|
||||
sheet = hssfworkbook.GetSheetAt(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
XSSFWorkbook xssfworkbook = new XSSFWorkbook(fileStream);
|
||||
sheet = xssfworkbook.GetSheetAt(0);
|
||||
}
|
||||
System.Collections.IEnumerator rows = sheet.GetRowEnumerator();
|
||||
IRow headerRow = sheet.GetRow(0);
|
||||
int cellCount = headerRow.LastCellNum;
|
||||
for (int j = 0; j < cellCount; j++)
|
||||
{
|
||||
ICell cell = headerRow.GetCell(j);
|
||||
dt.Columns.Add(cell.ToString());
|
||||
}
|
||||
for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
|
||||
{
|
||||
IRow row = sheet.GetRow(i);
|
||||
DataRow dataRow = dt.NewRow();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; j++)
|
||||
{
|
||||
if (row.GetCell(j) != null)
|
||||
dataRow[j] = row.GetCell(j).ToString();
|
||||
}
|
||||
|
||||
dt.Rows.Add(dataRow);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region RGB颜色转NPOI颜色
|
||||
private static short GetXLColour(HSSFWorkbook workbook, System.Drawing.Color SystemColour)
|
||||
{
|
||||
short s = 0;
|
||||
HSSFPalette XlPalette = workbook.GetCustomPalette();
|
||||
NPOI.HSSF.Util.HSSFColor XlColour = XlPalette.FindColor(SystemColour.R, SystemColour.G, SystemColour.B);
|
||||
if (XlColour == null)
|
||||
{
|
||||
if (NPOI.HSSF.Record.PaletteRecord.STANDARD_PALETTE_SIZE < 255)
|
||||
{
|
||||
XlColour = XlPalette.FindSimilarColor(SystemColour.R, SystemColour.G, SystemColour.B);
|
||||
s = XlColour.Indexed;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
s = XlColour.Indexed;
|
||||
return s;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设置列的对齐方式
|
||||
/// <summary>
|
||||
/// 设置对齐方式
|
||||
/// </summary>
|
||||
/// <param name="style"></param>
|
||||
/// <returns></returns>
|
||||
private static HorizontalAlignment getAlignment(string style)
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case "center":
|
||||
return HorizontalAlignment.Center;
|
||||
case "left":
|
||||
return HorizontalAlignment.Left;
|
||||
case "right":
|
||||
return HorizontalAlignment.Right;
|
||||
case "fill":
|
||||
return HorizontalAlignment.Fill;
|
||||
case "justify":
|
||||
return HorizontalAlignment.Justify;
|
||||
case "centerselection":
|
||||
return HorizontalAlignment.CenterSelection;
|
||||
case "distributed":
|
||||
return HorizontalAlignment.Distributed;
|
||||
}
|
||||
return NPOI.SS.UserModel.HorizontalAlignment.General;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Helpers.Excel.Model
|
||||
{
|
||||
public class ColumnModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 列名
|
||||
/// </summary>
|
||||
public string Column { get; set; }
|
||||
/// <summary>
|
||||
/// Excel列名
|
||||
/// </summary>
|
||||
public string ExcelColumn { get; set; }
|
||||
/// <summary>
|
||||
/// 宽度
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
/// <summary>
|
||||
/// 前景色
|
||||
/// </summary>
|
||||
public System.Drawing.Color ForeColor { get; set; }
|
||||
/// <summary>
|
||||
/// 背景色
|
||||
/// </summary>
|
||||
public System.Drawing.Color Background { get; set; }
|
||||
/// <summary>
|
||||
/// 字体
|
||||
/// </summary>
|
||||
public string Font { get; set; }
|
||||
/// <summary>
|
||||
/// 字号
|
||||
/// </summary>
|
||||
public short Point { get; set; }
|
||||
/// <summary>
|
||||
///对齐方式
|
||||
///left 左
|
||||
///center 中间
|
||||
///right 右
|
||||
///fill 填充
|
||||
///justify 两端对齐
|
||||
///centerselection 跨行居中
|
||||
///distributed
|
||||
/// </summary>
|
||||
public string Alignment { get; set; }
|
||||
/// <summary>
|
||||
/// 时间格式化
|
||||
/// </summary>
|
||||
public string DateFormat { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,407 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Infrastructure.Extensions;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class FileHelper
|
||||
{
|
||||
private static object _filePathObj = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 通过迭代器读取平面文件行内容(必须是带有\r\n换行的文件,百万行以上的内容读取效率存在问题,适用于100M左右文件,行100W内,超出的会有卡顿)
|
||||
/// </summary>
|
||||
/// <param name="fullPath">文件全路径</param>
|
||||
/// <param name="page">分页页数</param>
|
||||
/// <param name="pageSize">分页大小</param>
|
||||
/// <param name="seekEnd"> 是否最后一行向前读取,默认从前向后读取</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> ReadPageLine(string fullPath, int page, int pageSize, bool seekEnd = false)
|
||||
{
|
||||
if (page <= 0)
|
||||
{
|
||||
page = 1;
|
||||
}
|
||||
fullPath = StringExtension.ReplacePath(fullPath);
|
||||
var lines = File.ReadLines(fullPath, Encoding.UTF8);
|
||||
if (seekEnd)
|
||||
{
|
||||
int lineCount = lines.Count();
|
||||
int linPageCount = (int)Math.Ceiling(lineCount / (pageSize * 1.00));
|
||||
//超过总页数,不处理
|
||||
if (page > linPageCount)
|
||||
{
|
||||
page = 0;
|
||||
pageSize = 0;
|
||||
}
|
||||
else if (page == linPageCount)//最后一页,取最后一页剩下所有的行
|
||||
{
|
||||
pageSize = lineCount - (page - 1) * pageSize;
|
||||
if (page == 1)
|
||||
{
|
||||
page = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
page = lines.Count() - page * pageSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
page = lines.Count() - page * pageSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
page = (page - 1) * pageSize;
|
||||
}
|
||||
lines = lines.Skip(page).Take(pageSize);
|
||||
|
||||
var enumerator = lines.GetEnumerator();
|
||||
int count = 1;
|
||||
while (enumerator.MoveNext() || count <= pageSize)
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
count++;
|
||||
}
|
||||
enumerator.Dispose();
|
||||
}
|
||||
public static bool FileExists(string path)
|
||||
{
|
||||
return File.Exists(StringExtension.ReplacePath(path));
|
||||
}
|
||||
|
||||
public static string GetCurrentDownLoadPath()
|
||||
{
|
||||
return ("Download\\").MapPath();
|
||||
}
|
||||
|
||||
public static bool DirectoryExists(string path)
|
||||
{
|
||||
return Directory.Exists(StringExtension.ReplacePath(path));
|
||||
}
|
||||
|
||||
|
||||
public static string Read_File(string fullpath, string filename, string suffix)
|
||||
{
|
||||
return ReadFile((fullpath + "\\" + filename + suffix).MapPath());
|
||||
}
|
||||
public static string ReadFile(string fullName)
|
||||
{
|
||||
// Encoding code = Encoding.GetEncoding(); //Encoding.GetEncoding("gb2312");
|
||||
string temp = fullName.MapPath().ReplacePath();
|
||||
string str = "";
|
||||
if (!File.Exists(temp))
|
||||
{
|
||||
return str;
|
||||
}
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(temp);
|
||||
str = sr.ReadToEnd(); // 读取文件
|
||||
}
|
||||
catch { }
|
||||
sr?.Close();
|
||||
sr?.Dispose();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 取后缀名
|
||||
/// </summary>
|
||||
/// <param name="filename">文件名</param>
|
||||
/// <returns>.gif|.html格式</returns>
|
||||
public static string GetPostfixStr(string filename)
|
||||
{
|
||||
int start = filename.LastIndexOf(".");
|
||||
int length = filename.Length;
|
||||
string postfix = filename.Substring(start, length - start);
|
||||
return postfix;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="path">路径 </param>
|
||||
/// <param name="fileName">文件名</param>
|
||||
/// <param name="content">写入的内容</param>
|
||||
/// <param name="appendToLast">是否将内容添加到未尾,默认不添加</param>
|
||||
public static void WriteFile(string path, string fileName, string content, bool appendToLast = false)
|
||||
{
|
||||
path = StringExtension.ReplacePath(path);
|
||||
fileName = StringExtension.ReplacePath(fileName);
|
||||
if (!Directory.Exists(path))//如果不存在就创建file文件夹
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
using (FileStream stream = File.Open(Path.Combine(path, fileName), FileMode.OpenOrCreate, FileAccess.Write))
|
||||
{
|
||||
byte[] by = Encoding.Default.GetBytes(content);
|
||||
if (appendToLast)
|
||||
{
|
||||
stream.Position = stream.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.SetLength(0);
|
||||
}
|
||||
stream.Write(by, 0, by.Length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 追加文件
|
||||
/// </summary>
|
||||
/// <param name="Path">文件路径</param>
|
||||
/// <param name="strings">内容</param>
|
||||
public static void FileAdd(string Path, string strings)
|
||||
{
|
||||
StreamWriter sw = File.AppendText(StringExtension.ReplacePath(Path));
|
||||
sw.Write(strings);
|
||||
sw.Flush();
|
||||
sw.Close();
|
||||
sw.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 拷贝文件
|
||||
/// </summary>
|
||||
/// <param name="OrignFile">原始文件</param>
|
||||
/// <param name="NewFile">新文件路径</param>
|
||||
public static void FileCoppy(string OrignFile, string NewFile)
|
||||
{
|
||||
File.Copy(StringExtension.ReplacePath(OrignFile), StringExtension.ReplacePath(NewFile), true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除文件
|
||||
/// </summary>
|
||||
/// <param name="Path">路径</param>
|
||||
public static void FileDel(string Path)
|
||||
{
|
||||
File.Delete(StringExtension.ReplacePath(Path));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动文件
|
||||
/// </summary>
|
||||
/// <param name="OrignFile">原始路径</param>
|
||||
/// <param name="NewFile">新路径</param>
|
||||
public static void FileMove(string OrignFile, string NewFile)
|
||||
{
|
||||
File.Move(StringExtension.ReplacePath(OrignFile), StringExtension.ReplacePath(NewFile));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在当前目录下创建目录
|
||||
/// </summary>
|
||||
/// <param name="OrignFolder">当前目录</param>
|
||||
/// <param name="NewFloder">新目录</param>
|
||||
public static void FolderCreate(string OrignFolder, string NewFloder)
|
||||
{
|
||||
Directory.SetCurrentDirectory(StringExtension.ReplacePath(OrignFolder));
|
||||
Directory.CreateDirectory(StringExtension.ReplacePath(NewFloder));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建文件夹
|
||||
/// </summary>
|
||||
/// <param name="Path"></param>
|
||||
public static void FolderCreate(string Path)
|
||||
{
|
||||
// 判断目标目录是否存在如果不存在则新建之
|
||||
if (!Directory.Exists(StringExtension.ReplacePath(Path)))
|
||||
Directory.CreateDirectory(StringExtension.ReplacePath(Path));
|
||||
}
|
||||
|
||||
|
||||
public static void FileCreate(string Path)
|
||||
{
|
||||
FileInfo CreateFile = new FileInfo(StringExtension.ReplacePath(Path)); //创建文件
|
||||
if (!CreateFile.Exists)
|
||||
{
|
||||
FileStream FS = CreateFile.Create();
|
||||
FS.Close();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 递归删除文件夹目录及文件
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <returns></returns>
|
||||
public static void DeleteFolder(string dir)
|
||||
{
|
||||
dir = StringExtension.ReplacePath(dir);
|
||||
if (Directory.Exists(dir)) //如果存在这个文件夹删除之
|
||||
{
|
||||
foreach (string d in Directory.GetFileSystemEntries(dir))
|
||||
{
|
||||
if (File.Exists(d))
|
||||
File.Delete(d); //直接删除其中的文件
|
||||
else
|
||||
DeleteFolder(d); //递归删除子文件夹
|
||||
}
|
||||
Directory.Delete(dir, true); //删除已空文件夹
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 指定文件夹下面的所有内容copy到目标文件夹下面
|
||||
/// </summary>
|
||||
/// <param name="srcPath">原始路径</param>
|
||||
/// <param name="aimPath">目标文件夹</param>
|
||||
public static void CopyDir(string srcPath, string aimPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
aimPath = StringExtension.ReplacePath(aimPath);
|
||||
// 检查目标目录是否以目录分割字符结束如果不是则添加之
|
||||
if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar)
|
||||
aimPath += Path.DirectorySeparatorChar;
|
||||
// 判断目标目录是否存在如果不存在则新建之
|
||||
if (!Directory.Exists(aimPath))
|
||||
Directory.CreateDirectory(aimPath);
|
||||
// 得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组
|
||||
//如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法
|
||||
//string[] fileList = Directory.GetFiles(srcPath);
|
||||
string[] fileList = Directory.GetFileSystemEntries(StringExtension.ReplacePath(srcPath));
|
||||
//遍历所有的文件和目录
|
||||
foreach (string file in fileList)
|
||||
{
|
||||
//先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
|
||||
|
||||
if (Directory.Exists(file))
|
||||
CopyDir(file, aimPath + Path.GetFileName(file));
|
||||
//否则直接Copy文件
|
||||
else
|
||||
File.Copy(file, aimPath + Path.GetFileName(file), true);
|
||||
}
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
throw new Exception(ee.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件夹大小
|
||||
/// </summary>
|
||||
/// <param name="dirPath">文件夹路径</param>
|
||||
/// <returns></returns>
|
||||
public static long GetDirectoryLength(string dirPath)
|
||||
{
|
||||
dirPath = StringExtension.ReplacePath(dirPath);
|
||||
if (!Directory.Exists(dirPath))
|
||||
return 0;
|
||||
long len = 0;
|
||||
DirectoryInfo di = new DirectoryInfo(dirPath);
|
||||
foreach (FileInfo fi in di.GetFiles())
|
||||
{
|
||||
len += fi.Length;
|
||||
}
|
||||
DirectoryInfo[] dis = di.GetDirectories();
|
||||
if (dis.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < dis.Length; i++)
|
||||
{
|
||||
len += GetDirectoryLength(dis[i].FullName);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件详细属性
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件详细路径</param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileAttibe(string filePath)
|
||||
{
|
||||
string str = "";
|
||||
filePath = StringExtension.ReplacePath(filePath);
|
||||
System.IO.FileInfo objFI = new System.IO.FileInfo(filePath);
|
||||
str += "详细路径:" + objFI.FullName + "<br>文件名称:" + objFI.Name + "<br>文件长度:" + objFI.Length.ToString() + "字节<br>创建时间" + objFI.CreationTime.ToString() + "<br>最后访问时间:" + objFI.LastAccessTime.ToString() + "<br>修改时间:" + objFI.LastWriteTime.ToString() + "<br>所在目录:" + objFI.DirectoryName + "<br>扩展名:" + objFI.Extension;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 括号匹配算法
|
||||
/// </summary>
|
||||
/// <param name="dataStr">原始字符串</param>
|
||||
/// <param name="leftCode">左匹配符号</param>
|
||||
/// <param name="rightCode">右匹配符号</param>
|
||||
/// <returns></returns>
|
||||
private static string parenthesisMatch(string dataStr, char leftCode, char rightCode)
|
||||
{
|
||||
Stack stack = new Stack();
|
||||
|
||||
string cut_text = "";
|
||||
|
||||
for (int i = 0; i < dataStr.Length; ++i)
|
||||
{
|
||||
char ch = dataStr[i];
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
cut_text += ch;
|
||||
}
|
||||
if (ch == leftCode)
|
||||
{
|
||||
stack.Push(ch);
|
||||
}
|
||||
if (ch == rightCode)
|
||||
{
|
||||
stack.Pop();
|
||||
if (0 == stack.Count)
|
||||
{
|
||||
return cut_text.Substring(0, cut_text.Length - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 替换内容(正则 + 括号匹配算法)
|
||||
/// </summary>
|
||||
/// <param name="path">文件路径</param>
|
||||
/// <param name="addStr">追加内容</param>
|
||||
public static void RegxAddContentByParenthesis(string path, string addStr)
|
||||
{
|
||||
path = StringExtension.ReplacePath(path);
|
||||
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
StreamReader sr = new StreamReader(fs);
|
||||
string originStr = sr.ReadToEnd();
|
||||
|
||||
string pattern = @"DbContext\s*?({.*)";
|
||||
if (Regex.IsMatch(originStr, pattern))
|
||||
{
|
||||
Match match = Regex.Match(originStr, pattern, RegexOptions.Singleline);
|
||||
string cut_str = parenthesisMatch(match.Groups[1].Value, '{', '}'); // 剪切内容(原内容)
|
||||
string new_str = cut_str + "\r\n " + addStr + "\r\n"; // 实际更新内容
|
||||
originStr = originStr.Replace(cut_str, new_str);
|
||||
}
|
||||
|
||||
sr.Close();
|
||||
fs.Close();
|
||||
FileStream fs2 = new FileStream(path, FileMode.Open, FileAccess.Write);
|
||||
StreamWriter sw = new StreamWriter(fs2);
|
||||
sw.WriteLine(originStr);
|
||||
sw.Close();
|
||||
fs2.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// List转成Tree
|
||||
/// <para>李玉宝新增于2016-10-09 19:54:07</para>
|
||||
/// </summary>
|
||||
public static class GenericHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates tree of items from item list
|
||||
/// </summary>
|
||||
///
|
||||
/// <typeparam name="T">Type of item in collection</typeparam>
|
||||
/// <typeparam name="K">Type of parent_id</typeparam>
|
||||
///
|
||||
/// <param name="collection">Collection of items</param>
|
||||
/// <param name="idSelector">Function extracting item's id</param>
|
||||
/// <param name="parentIdSelector">Function extracting item's parent_id</param>
|
||||
/// <param name="rootId">Root element id</param>
|
||||
///
|
||||
/// <returns>Tree of items</returns>
|
||||
public static IEnumerable<TreeItem<T>> GenerateTree<T, K>(
|
||||
this IEnumerable<T> collection,
|
||||
Func<T, K> idSelector,
|
||||
Func<T, K> parentIdSelector,
|
||||
K rootId = default(K))
|
||||
{
|
||||
foreach (var c in collection.Where(u =>
|
||||
{
|
||||
var selector = parentIdSelector(u);
|
||||
return (rootId == null && selector == null)
|
||||
|| (rootId != null && rootId.Equals(selector));
|
||||
}))
|
||||
{
|
||||
yield return new TreeItem<T>
|
||||
{
|
||||
Item = c,
|
||||
Children = collection.GenerateTree(idSelector, parentIdSelector, idSelector(c))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把数组转为逗号连接的字符串
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="Str"></param>
|
||||
/// <returns></returns>
|
||||
public static string ArrayToString(dynamic data, string Str)
|
||||
{
|
||||
string resStr = Str;
|
||||
foreach (var item in data)
|
||||
{
|
||||
if (resStr != "")
|
||||
{
|
||||
resStr += ",";
|
||||
}
|
||||
|
||||
if (item is string)
|
||||
{
|
||||
resStr += item;
|
||||
}
|
||||
else
|
||||
{
|
||||
resStr += item.Value;
|
||||
|
||||
}
|
||||
}
|
||||
return resStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,478 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Security;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class HIKOpenAPI
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="api"></param>
|
||||
/// <param name="body"></param>
|
||||
/// <param name="ak"></param>
|
||||
/// <param name="sk"></param>
|
||||
/// <returns></returns>
|
||||
public static string HttpPost(string url, string api, string body, string ak, string sk)
|
||||
{
|
||||
|
||||
var headers = new Dictionary<string, string> { { "Accept", "*/*" }, { "Content-Type", "application/json" } };
|
||||
|
||||
var request = new Request(Method.POST_STRING, url, api, ak, sk, 10000)
|
||||
{
|
||||
Headers = headers,
|
||||
SignHeaderPrefixList = null,
|
||||
Querys = null,
|
||||
StringBody = body
|
||||
};
|
||||
|
||||
var result = DoPoststring(request.Host, request.Path, request.Timeout, request.Headers, request.Querys, request.StringBody, request.SignHeaderPrefixList, request.AppKey, request.AppSecret, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
//Post请求方法
|
||||
public static string DoPoststring(string host, string path, int connectTimeout, Dictionary<string, string> headers,
|
||||
Dictionary<string, string> querys, string body, List<string> signHeaderPrefixList, string appKey,
|
||||
string appSecret, bool autoDown)
|
||||
{
|
||||
try
|
||||
{
|
||||
headers = initialBasicHeader("POST", path, headers, querys, null, signHeaderPrefixList, appKey,
|
||||
appSecret);
|
||||
ServicePointManager.ServerCertificateValidationCallback =
|
||||
RemoteCertificateValidate;
|
||||
//验证服务器证书回调自动验证
|
||||
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 |
|
||||
// SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(initUrl(host, path, querys));
|
||||
request.KeepAlive = false;
|
||||
request.ProtocolVersion = HttpVersion.Version10;
|
||||
//设置HTTP协议的并发连接数
|
||||
//ServicePointManager.DefaultConnectionLimit = 512;
|
||||
//关闭重定向
|
||||
request.AllowAutoRedirect = true;
|
||||
request.Method = "POST";
|
||||
request.Timeout = connectTimeout;
|
||||
string accept = headers["Accept"];
|
||||
request.Accept = accept;
|
||||
string contentType = headers["Content-Type"];
|
||||
request.ContentType = contentType;
|
||||
|
||||
foreach (string headerKey in headers.Keys)
|
||||
{
|
||||
if (headerKey.Contains("x-ca-"))
|
||||
{
|
||||
request.Headers.Add(headerKey + ":" +
|
||||
(string.IsNullOrWhiteSpace(headers[headerKey]) ? "" : headers[headerKey]));
|
||||
}
|
||||
if (headerKey.Equals("tagId"))
|
||||
{
|
||||
request.Headers.Add(headerKey + ":" +
|
||||
(string.IsNullOrWhiteSpace(headers[headerKey]) ? "" : headers[headerKey]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
byte[] postBytes = Encoding.UTF8.GetBytes(body);
|
||||
request.ContentLength = postBytes.Length;
|
||||
Stream requestStream = request.GetRequestStream();
|
||||
|
||||
requestStream.Write(postBytes, 0, postBytes.Length);
|
||||
requestStream.Close();
|
||||
}
|
||||
|
||||
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
var result = "";
|
||||
if (response.StatusCode != HttpStatusCode.OK) return result;
|
||||
using (StreamReader rdr = new StreamReader(response.GetResponseStream()))
|
||||
{
|
||||
result = rdr.ReadToEnd();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject(new { code = "404", msg = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//获取当时时间戳
|
||||
public static long GetTimestamp(DateTime time)
|
||||
{
|
||||
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
|
||||
long t = (time.Ticks - startTime.Ticks) / 10000; //除10000调整为13位
|
||||
return t;
|
||||
|
||||
}
|
||||
|
||||
private static bool RemoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain,
|
||||
SslPolicyErrors error)
|
||||
{
|
||||
//为了通过证书验证,总是返回true
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> initialBasicHeader(string method, string path,
|
||||
Dictionary<string, string> headers, Dictionary<string, string> querys, Dictionary<string, string> bodys,
|
||||
List<string> signHeaderPrefixList, string appKey, string appSecret) //throws MalformedURLException
|
||||
{
|
||||
if (headers == null)
|
||||
{
|
||||
headers = new Dictionary<string, string>();
|
||||
}
|
||||
headers["x-ca-timestamp"] = GetTimestamp(DateTime.Now).ToString();
|
||||
headers["x-ca-nonce"] = System.Guid.NewGuid().ToString();
|
||||
headers["x-ca-key"] = appKey;
|
||||
headers["x-ca-signature"] = sign(appSecret, method, path, headers, querys, bodys, signHeaderPrefixList);
|
||||
|
||||
return headers;
|
||||
//https://223.99.16.253:6114/pic?
|
||||
//5d00=a202l94-do7b18*35d69188-64fbf0ebc**561===sp**715=7t7662209067=1l3*1513o6*720-=46fe44pi1e9o=0-9e00b0
|
||||
//&AccessKeyId=Qrq2LsyWF6GSM0zm&Expires=1677046120&Signature=Bw7dKuV6CX7w3ev56u6jBwRuGwU=
|
||||
}
|
||||
|
||||
public static string initUrl(string host, string path, Dictionary<string, string> querys)
|
||||
//throws UnsupportedEncodingException
|
||||
{
|
||||
StringBuilder sbUrl = new StringBuilder();
|
||||
sbUrl.Append(host);
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
sbUrl.Append(path);
|
||||
}
|
||||
|
||||
if (null != querys)
|
||||
{
|
||||
StringBuilder sbQuery = new StringBuilder();
|
||||
|
||||
foreach (string queryKey in querys.Keys)
|
||||
{
|
||||
if (0 < sbQuery.Length)
|
||||
{
|
||||
sbQuery.Append("&");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(queryKey) && !string.IsNullOrWhiteSpace(querys[queryKey]))
|
||||
{
|
||||
sbQuery.Append(querys[queryKey]);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(queryKey))
|
||||
{
|
||||
sbQuery.Append(queryKey);
|
||||
if (!string.IsNullOrWhiteSpace(querys[queryKey]))
|
||||
{
|
||||
sbQuery.Append("=").Append(HttpUtility.UrlEncode(querys[queryKey], Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < sbQuery.Length)
|
||||
{
|
||||
sbUrl.Append("?").Append(sbQuery);
|
||||
}
|
||||
}
|
||||
return sbUrl.ToString();
|
||||
}
|
||||
|
||||
public static string sign(string secret, string method, string path, Dictionary<string, string> headers,
|
||||
Dictionary<string, string> querys, Dictionary<string, string> bodys, List<string> signHeaderPrefixList)
|
||||
{
|
||||
try
|
||||
{
|
||||
//return HmacSHA256(buildstringToSign(method, path, headers, querys, bodys, signHeaderPrefixList), secret);
|
||||
|
||||
/*---message里的内容---*/
|
||||
//POST
|
||||
//*/*
|
||||
//application/json
|
||||
//x-ca-key:23125513
|
||||
//x-ca-nonce:12d28d90-a7c3-45cc-ae6a-0cc8d5e22118
|
||||
//x-ca-timestamp:1544495633599
|
||||
//artemis/api/resource/v1/org/advance/orgList
|
||||
string message = buildstringToSign(method, path, headers, querys, bodys, signHeaderPrefixList);
|
||||
|
||||
|
||||
|
||||
return HmacSHA256(message, secret);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public static string buildstringToSign(string method, string path, Dictionary<string, string> headers,
|
||||
Dictionary<string, string> querys, Dictionary<string, string> bodys, List<string> signHeaderPrefixList)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(method.ToUpper()).Append("\n");
|
||||
if (null != headers)
|
||||
{
|
||||
if (null != headers["Accept"])
|
||||
{
|
||||
sb.Append((string)headers["Accept"]);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
if (headers.Keys.Contains("Content-MD5") && null != headers["Content-MD5"])
|
||||
{
|
||||
sb.Append((string)headers["Content-MD5"]);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
if (null != headers["Content-Type"])
|
||||
{
|
||||
sb.Append((string)headers["Content-Type"]);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
if (headers.Keys.Contains("Date") && null != headers["Date"])
|
||||
{
|
||||
sb.Append((string)headers["Date"]);
|
||||
sb.Append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append(buildHeaders(headers, signHeaderPrefixList));
|
||||
sb.Append(buildResource(path, querys, bodys));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string buildHeaders(Dictionary<string, string> headers, List<string> signHeaderPrefixList)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (null != signHeaderPrefixList)
|
||||
{
|
||||
signHeaderPrefixList.Remove("x-ca-signature");
|
||||
signHeaderPrefixList.Remove("Accept");
|
||||
signHeaderPrefixList.Remove("Content-MD5");
|
||||
signHeaderPrefixList.Remove("Content-Type");
|
||||
signHeaderPrefixList.Remove("Date");
|
||||
signHeaderPrefixList.Sort();
|
||||
}
|
||||
|
||||
if (null != headers)
|
||||
{
|
||||
Dictionary<string, string> sortDictionary = new Dictionary<string, string>();
|
||||
sortDictionary = headers;
|
||||
//按key值升序排序
|
||||
var dicSort = from objDic in sortDictionary orderby objDic.Key ascending select objDic;
|
||||
|
||||
StringBuilder signHeadersStringBuilder = new StringBuilder();
|
||||
|
||||
foreach (KeyValuePair<string, string> kvp in dicSort)
|
||||
{
|
||||
if (kvp.Key.Replace(" ", "").Contains("x-ca-"))
|
||||
{
|
||||
sb.Append(kvp.Key + ":");
|
||||
if (!string.IsNullOrWhiteSpace(kvp.Value))
|
||||
{
|
||||
sb.Append(kvp.Value);
|
||||
}
|
||||
sb.Append("\n");
|
||||
if (signHeadersStringBuilder.Length > 0)
|
||||
{
|
||||
signHeadersStringBuilder.Append(",");
|
||||
}
|
||||
signHeadersStringBuilder.Append(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
headers.Add("x-ca-signature-headers", signHeadersStringBuilder.ToString());
|
||||
}
|
||||
|
||||
//x-ca-key:23125513
|
||||
//x-ca-nonce:12d28d90-a7c3-45cc-ae6a-0cc8d5e22118
|
||||
//x-ca-timestamp:1544495633599
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string buildResource(string path, Dictionary<string, string> querys, Dictionary<string, string> bodys)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
sb.Append(path);
|
||||
}
|
||||
|
||||
Dictionary<string, string> sortDictionary = new Dictionary<string, string>();
|
||||
if (querys != null)
|
||||
{
|
||||
//按key值升序排序
|
||||
var dicSort = from objDic in querys orderby objDic.Key ascending select objDic;
|
||||
foreach (KeyValuePair<string, string> kvp in dicSort)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(kvp.Key))
|
||||
{
|
||||
sortDictionary[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bodys != null)
|
||||
{
|
||||
//按key值升序排序
|
||||
var dicSort = from objDic in bodys orderby objDic.Key ascending select objDic;
|
||||
foreach (KeyValuePair<string, string> kvp in dicSort)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(kvp.Key))
|
||||
{
|
||||
sortDictionary[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sbParam = new StringBuilder();
|
||||
|
||||
//按key值升序排序
|
||||
var dicSortDictionary = from objDic in sortDictionary orderby objDic.Key ascending select objDic;
|
||||
foreach (KeyValuePair<string, string> kvp in dicSortDictionary)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(kvp.Key))
|
||||
{
|
||||
if (sbParam.Length > 0)
|
||||
{
|
||||
sbParam.Append("&");
|
||||
}
|
||||
sbParam.Append(kvp.Key);
|
||||
if (!string.IsNullOrWhiteSpace(kvp.Value))
|
||||
{
|
||||
sbParam.Append("=").Append(kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < sbParam.Length)
|
||||
{
|
||||
sb.Append("?");
|
||||
sb.Append(sbParam);
|
||||
}
|
||||
//artemis/api/resource/v1/org/advance/orgList
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string HmacSHA256(string message, string secret)
|
||||
{
|
||||
secret = secret ?? "";
|
||||
var encoding = new System.Text.UTF8Encoding();
|
||||
byte[] keyByte = encoding.GetBytes(secret);
|
||||
byte[] messageBytes = encoding.GetBytes(message);
|
||||
using (var hmacsha256 = new HMACSHA256(keyByte))
|
||||
{
|
||||
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
|
||||
return Convert.ToBase64String(hashmessage);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> ConvertMapTimeStyle(Dictionary<string, object> paramMap)
|
||||
{
|
||||
Dictionary<string, object> timeMap = new Dictionary<string, object>();
|
||||
try
|
||||
{
|
||||
foreach (string key in paramMap.Keys)
|
||||
{
|
||||
|
||||
object mapValueObj = paramMap[key];
|
||||
Dictionary<string, object> dic = mapValueObj as Dictionary<string, object>;
|
||||
if (dic != null)
|
||||
{
|
||||
ConvertMapTimeStyle(dic);
|
||||
}
|
||||
//时间格式参数转为ISO8601
|
||||
DateTime mapDate;
|
||||
if (DateTime.TryParse(paramMap[key].ToString(), out mapDate))
|
||||
{
|
||||
string ISO8601time = mapDate.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz");
|
||||
timeMap.Add(key, ISO8601time);
|
||||
}
|
||||
}
|
||||
if (timeMap.Count > 0)
|
||||
{
|
||||
foreach (string key in timeMap.Keys)
|
||||
{
|
||||
paramMap[key] = timeMap[key];
|
||||
}
|
||||
}
|
||||
return paramMap;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return paramMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum Method
|
||||
{
|
||||
GET,
|
||||
POST_FORM,
|
||||
POST_STRING,
|
||||
POST_BYTES,
|
||||
PUT_FORM,
|
||||
PUT_STRING,
|
||||
PUT_BYTES,
|
||||
DELETE
|
||||
}
|
||||
|
||||
public class Request
|
||||
{
|
||||
public Request()
|
||||
{
|
||||
}
|
||||
|
||||
public Request(Method method, string host, string path, string appKey, string appSecret, int timeout)
|
||||
{
|
||||
this.Method = method;
|
||||
this.Host = host;
|
||||
this.Path = path;
|
||||
this.AppKey = appKey;
|
||||
this.AppSecret = appSecret;
|
||||
this.Timeout = timeout;
|
||||
}
|
||||
|
||||
public Method Method { get; set; }
|
||||
|
||||
public string Host { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public string AppKey { get; set; }
|
||||
|
||||
public string AppSecret { get; set; }
|
||||
|
||||
public int Timeout { get; set; }
|
||||
|
||||
public Dictionary<string, string> Headers { get; set; }
|
||||
|
||||
public Dictionary<string, string> Querys { get; set; }
|
||||
|
||||
public Dictionary<string, string> Bodys { get; set; }
|
||||
|
||||
public string StringBody { get; set; }
|
||||
|
||||
public byte[] BytesBody { get; set; }
|
||||
|
||||
public List<string> SignHeaderPrefixList { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// http请求类
|
||||
/// </summary>
|
||||
public class HttpHelper
|
||||
{
|
||||
private HttpClient _httpClient;
|
||||
private string _baseIPAddress;
|
||||
|
||||
/// <param name="ipaddress">请求的基础IP,例如:http://192.168.0.33:8080/ </param>
|
||||
public HttpHelper(string ipaddress = "")
|
||||
{
|
||||
this._baseIPAddress = ipaddress;
|
||||
_httpClient = new HttpClient { BaseAddress = new Uri(_baseIPAddress) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建带用户信息的请求客户端
|
||||
/// </summary>
|
||||
/// <param name="userName">用户账号</param>
|
||||
/// <param name="pwd">用户密码,当WebApi端不要求密码验证时,可传空串</param>
|
||||
/// <param name="uriString">The URI string.</param>
|
||||
public HttpHelper(string userName, string pwd = "", string uriString = "")
|
||||
: this(uriString)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(userName))
|
||||
{
|
||||
_httpClient.DefaultRequestHeaders.Authorization = CreateBasicCredentials(userName, pwd);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get请求数据
|
||||
/// /// <para>最终以url参数的方式提交</para>
|
||||
/// <para>yubaolee 2016-3-3 重构与post同样异步调用</para>
|
||||
/// </summary>
|
||||
/// <param name="parameters">参数字典,可为空</param>
|
||||
/// <param name="requestUri">例如/api/Files/UploadFile</param>
|
||||
/// <returns></returns>
|
||||
public string Get(Dictionary<string, string> parameters, string requestUri)
|
||||
{
|
||||
if (parameters != null)
|
||||
{
|
||||
var strParam = string.Join("&", parameters.Select(o => o.Key + "=" + o.Value));
|
||||
requestUri = string.Concat(ConcatURL(requestUri), '?', strParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestUri = ConcatURL(requestUri);
|
||||
}
|
||||
|
||||
var result = _httpClient.GetStringAsync(requestUri);
|
||||
return result.Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get请求数据
|
||||
/// <para>最终以url参数的方式提交</para>
|
||||
/// </summary>
|
||||
/// <param name="parameters">参数字典</param>
|
||||
/// <param name="requestUri">例如/api/Files/UploadFile</param>
|
||||
/// <returns>实体对象</returns>
|
||||
public T Get<T>(Dictionary<string, string> parameters, string requestUri) where T : class
|
||||
{
|
||||
string jsonString = Get(parameters, requestUri);
|
||||
if (string.IsNullOrEmpty(jsonString))
|
||||
return null;
|
||||
|
||||
return JsonHelper.Instance.Deserialize<T>(jsonString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以json的方式Post数据 返回string类型
|
||||
/// <para>最终以json的方式放置在http体中</para>
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="requestUri">例如/api/Files/UploadFile</param>
|
||||
/// <returns></returns>
|
||||
public string Post(object entity, string requestUri)
|
||||
{
|
||||
string request = string.Empty;
|
||||
if (entity != null)
|
||||
request = JsonHelper.Instance.Serialize(entity);
|
||||
HttpContent httpContent = new StringContent(request);
|
||||
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
return Post(requestUri, httpContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提交字典类型的数据
|
||||
/// <para>最终以formurlencode的方式放置在http体中</para>
|
||||
/// <para>李玉宝于2016-07-20 19:01:59</para>
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public string PostDicObj(Dictionary<string, object> para, string requestUri)
|
||||
{
|
||||
Dictionary<string, string> temp = new Dictionary<string, string>();
|
||||
foreach (var item in para)
|
||||
{
|
||||
if (item.Value != null)
|
||||
{
|
||||
if (item.Value.GetType().Name.ToLower() != "string")
|
||||
{
|
||||
temp.Add(item.Key, JsonHelper.Instance.Serialize(item.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.Add(item.Key, item.Value.ToString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
temp.Add(item.Key, "");
|
||||
}
|
||||
}
|
||||
|
||||
return PostDic(temp, requestUri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post Dic数据
|
||||
/// <para>最终以formurlencode的方式放置在http体中</para>
|
||||
/// <para>李玉宝于2016-07-15 15:28:41</para>
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public string PostDic(Dictionary<string, string> temp, string requestUri)
|
||||
{
|
||||
HttpContent httpContent = new FormUrlEncodedContent(temp);
|
||||
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
|
||||
return Post(requestUri, httpContent);
|
||||
}
|
||||
|
||||
public string PostByte(byte[] bytes, string requestUrl)
|
||||
{
|
||||
HttpContent content = new ByteArrayContent(bytes);
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||
return Post(requestUrl, content);
|
||||
}
|
||||
|
||||
private string Post(string requestUrl, HttpContent content)
|
||||
{
|
||||
var result = _httpClient.PostAsync(ConcatURL(requestUrl), content);
|
||||
return result.Result.Content.ReadAsStringAsync().Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把请求的URL相对路径组合成绝对路径
|
||||
/// <para>李玉宝于2016-07-21 9:54:07</para>
|
||||
/// </summary>
|
||||
private string ConcatURL(string requestUrl)
|
||||
{
|
||||
return new Uri(_httpClient.BaseAddress, requestUrl).OriginalString;
|
||||
}
|
||||
|
||||
private AuthenticationHeaderValue CreateBasicCredentials(string userName, string password)
|
||||
{
|
||||
string toEncode = userName + ":" + password;
|
||||
// The current HTTP specification says characters here are ISO-8859-1.
|
||||
// However, the draft specification for the next version of HTTP indicates this encoding is infrequently
|
||||
// used in practice and defines behavior only for ASCII.
|
||||
Encoding encoding = Encoding.GetEncoding("utf-8");
|
||||
byte[] toBase64 = encoding.GetBytes(toEncode);
|
||||
string parameter = Convert.ToBase64String(toBase64);
|
||||
|
||||
return new AuthenticationHeaderValue("Basic", parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Security;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class HttpMethods
|
||||
{
|
||||
//
|
||||
// 摘要:
|
||||
// 创建HttpClient
|
||||
public static HttpClient CreateHttpClient(string url, IDictionary<string, string> cookies = null)
|
||||
{
|
||||
HttpClientHandler httpClientHandler = new HttpClientHandler();
|
||||
Uri uri = new Uri(url);
|
||||
if (cookies != null)
|
||||
{
|
||||
foreach (string key in cookies.Keys)
|
||||
{
|
||||
string cookieHeader = key + "=" + cookies[key];
|
||||
httpClientHandler.CookieContainer.SetCookies(uri, cookieHeader);
|
||||
}
|
||||
}
|
||||
|
||||
if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback = (RemoteCertificateValidationCallback)Delegate.Combine(ServicePointManager.ServerCertificateValidationCallback, (RemoteCertificateValidationCallback)((object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true));
|
||||
return new HttpClient(httpClientHandler);
|
||||
}
|
||||
|
||||
return new HttpClient(httpClientHandler);
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// post 请求
|
||||
//
|
||||
// 参数:
|
||||
// url:
|
||||
// 请求地址
|
||||
//
|
||||
// jsonData:
|
||||
// 请求参数
|
||||
public static Task<string> Post(string url, string jsonData)
|
||||
{
|
||||
HttpClient httpClient = CreateHttpClient(url);
|
||||
StringContent stringContent = new StringContent(jsonData);
|
||||
stringContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
return httpClient.PostAsync(url, stringContent).Result.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// post 请求
|
||||
//
|
||||
// 参数:
|
||||
// url:
|
||||
// 请求地址
|
||||
public static Task<string> Post(string url)
|
||||
{
|
||||
HttpClient httpClient = CreateHttpClient(url);
|
||||
StringContent stringContent = new StringContent("");
|
||||
stringContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
return httpClient.PostAsync(url, stringContent).Result.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// post 请求
|
||||
//
|
||||
// 参数:
|
||||
// url:
|
||||
// 请求地址
|
||||
//
|
||||
// req:
|
||||
// 请求参数
|
||||
public static Task<string> Post(string url, byte[] req)
|
||||
{
|
||||
HttpClient httpClient = CreateHttpClient(url);
|
||||
ByteArrayContent content = new ByteArrayContent(req);
|
||||
return httpClient.PostAsync(url, content).Result.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// get 请求
|
||||
//
|
||||
// 参数:
|
||||
// url:
|
||||
// 请求地址
|
||||
public static Task<string> Get(string url)
|
||||
{
|
||||
HttpClient httpClient = CreateHttpClient(url);
|
||||
return httpClient.GetAsync(url).Result.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using System.Drawing.Imaging;
|
||||
using Image = System.Drawing.Image;
|
||||
|
||||
namespace Hopetry.App.Common;
|
||||
|
||||
public class ImageHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 图片转换成字节流
|
||||
/// </summary>
|
||||
/// <param name="img">要转换的Image对象</param>
|
||||
/// <returns>转换后返回的字节流</returns>
|
||||
public static Stream ImgToStream(Image img)
|
||||
{
|
||||
byte[] imgByte = ImgToByt(img);
|
||||
//img.Save(ms, img.RawFormat);//System.Drawing.Imaging.ImageFormat.Jpeg
|
||||
Stream stream = new MemoryStream(imgByte);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 图片转换成字节流
|
||||
/// </summary>
|
||||
/// <param name="img">要转换的Image对象</param>
|
||||
/// <returns>转换后返回的字节流</returns>
|
||||
public static byte[] ImgToByt(Image img)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] imagedata = null;
|
||||
img.Save(ms, ImageFormat.Jpeg);
|
||||
imagedata = ms.GetBuffer();
|
||||
return imagedata;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// <copyright file="ImgHelper.cs" company="openauth.net.cn">
|
||||
// Copyright (c) 2019 openauth.net.cn. All rights reserved.
|
||||
// </copyright>
|
||||
// <author>www.cnblogs.com/yubaolee</author>
|
||||
// <summary>生成缩略图</summary>
|
||||
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class ImgHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据已有图片生成缩略图
|
||||
/// <para>用法:MakeThumbnail(path, tpath, 120, 90, "H");</para>
|
||||
/// </summary>
|
||||
/// <param name="originalImagePath">源图片路径</param>
|
||||
/// <param name="thumbnailPath">缩略图保存路径</param>
|
||||
/// <param name="width">缩略图的宽度</param>
|
||||
/// <param name="height">缩略图高度</param>
|
||||
/// <param name="mode">缩略模式:H:指定高度,宽度按比例处理;W:指定宽度,高度按比例处理;HW按参数指定的高度和宽度</param>
|
||||
public static void MakeThumbnail(string originalImagePath,
|
||||
string thumbnailPath,
|
||||
int width = 120, int height = 90, string mode = "H")
|
||||
{
|
||||
using (var originalImage = Image.Load(originalImagePath))
|
||||
{
|
||||
int towidth = width; //缩略图宽度
|
||||
int toheight = height; //缩略图高度
|
||||
switch (mode)
|
||||
{
|
||||
case "HW": //指定高宽缩放(可能变形)
|
||||
break;
|
||||
case "W": //指定宽,高按比例
|
||||
toheight = originalImage.Height * width / originalImage.Width;
|
||||
break;
|
||||
case "H": //指定高,宽按比例
|
||||
towidth = originalImage.Width * height / originalImage.Height;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
originalImage.Mutate(x => x.Resize(towidth, toheight));
|
||||
originalImage.Save(thumbnailPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class Md5
|
||||
{
|
||||
public static string Encrypt(string str)
|
||||
{
|
||||
|
||||
string pwd = String.Empty;
|
||||
|
||||
MD5 md5 = MD5.Create();
|
||||
|
||||
// 编码UTF8/Unicode
|
||||
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
|
||||
|
||||
// 转换成字符串
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
//格式后的字符是小写的字母
|
||||
//如果使用大写(X)则格式后的字符是大写字符
|
||||
pwd = pwd + s[i].ToString("X");
|
||||
|
||||
}
|
||||
|
||||
return pwd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public class Md5Helper
|
||||
{
|
||||
//
|
||||
// 摘要:
|
||||
// MD5加密
|
||||
//
|
||||
// 参数:
|
||||
// str:
|
||||
// 加密字符
|
||||
//
|
||||
// code:
|
||||
// 加密位数16/32
|
||||
public static string Encrypt(string str, int code)
|
||||
{
|
||||
string result = string.Empty;
|
||||
if (code == 16)
|
||||
{
|
||||
result = Hash(str).Substring(8, 16);
|
||||
}
|
||||
|
||||
if (code == 32)
|
||||
{
|
||||
result = Hash(str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 32位MD5加密(小写)
|
||||
//
|
||||
// 参数:
|
||||
// input:
|
||||
// 输入字段
|
||||
public static string Hash(string input)
|
||||
{
|
||||
MD5CryptoServiceProvider mD5CryptoServiceProvider = new MD5CryptoServiceProvider();
|
||||
byte[] array = mD5CryptoServiceProvider.ComputeHash(Encoding.Default.GetBytes(input));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
stringBuilder.Append(array[i].ToString("x2"));
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : Infrastructure
|
||||
// Author : Yubao Li
|
||||
// Created : 11-23-2015
|
||||
//
|
||||
// Last Modified By : Yubao Li
|
||||
// Last Modified On : 11-23-2015
|
||||
// ***********************************************************************
|
||||
// <copyright file="ObjectHelper.cs" company="">
|
||||
// Copyright (c) . All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>
|
||||
//对象COPY/初始化帮助,通常是防止从视图中传过来的对象属性为空,这其赋初始值
|
||||
//</summary>
|
||||
// ***********************************************************************
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
public static class ObjectHelper
|
||||
{
|
||||
public static T CopyTo<T>(this object source) where T:class, new()
|
||||
{
|
||||
var result = new T();
|
||||
source.CopyTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void CopyTo<T>(this object source, T target)
|
||||
where T : class,new()
|
||||
{
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
target = new T();
|
||||
}
|
||||
|
||||
foreach (var property in target.GetType().GetProperties())
|
||||
{
|
||||
var propertyValue = source.GetType().GetProperty(property.Name).GetValue(source, null);
|
||||
if (propertyValue != null)
|
||||
{
|
||||
if (propertyValue.GetType().IsClass)
|
||||
{
|
||||
|
||||
}
|
||||
target.GetType().InvokeMember(property.Name, BindingFlags.SetProperty, null, target, new object[] { propertyValue });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach (var field in target.GetType().GetFields())
|
||||
{
|
||||
var fieldValue = source.GetType().GetField(field.Name).GetValue(source);
|
||||
if (fieldValue != null)
|
||||
{
|
||||
target.GetType().InvokeMember(field.Name, BindingFlags.SetField, null, target, new object[] { fieldValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
using System.Collections;
|
||||
using System.Text.RegularExpressions;
|
||||
using NetModular.DocX.Core;
|
||||
|
||||
|
||||
namespace Infrastructure.Helpers;
|
||||
|
||||
public class WordHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 导出word
|
||||
/// </summary>
|
||||
/// <param name="tempFilePath">模板路径</param>
|
||||
/// <param name="outPath">保存路径</param>
|
||||
/// <param name="data">数据</param>
|
||||
public static void Export(string tempFilePath, string outPath, Dictionary<string, object> data)
|
||||
{
|
||||
bool isrewrite = true; // true=覆盖已存在的同名文件,false则反之
|
||||
//if (!System.IO.Directory.Exists(outPath))
|
||||
//{
|
||||
// System.IO.Directory.CreateDirectory(outPath);
|
||||
//}
|
||||
File.Copy(tempFilePath, outPath, isrewrite);
|
||||
//新建一个Word文档,加载Load的方法和Create使用一样。
|
||||
using (DocX document = DocX.Load(outPath))
|
||||
{
|
||||
ReplaceDoc(document, data); //普通文本替换
|
||||
ReplaceTable(document, data); //表格处理
|
||||
ReplaceList(document, data); //文本列表处理
|
||||
|
||||
document.Save(); //保存
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReplaceDoc(DocX doc, Dictionary<string, object> data)
|
||||
{
|
||||
foreach (var item in doc.Paragraphs)
|
||||
{
|
||||
ReplaceParagraph(item, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReplaceList(DocX doc, Dictionary<string, object> data)
|
||||
{
|
||||
//一定要在 普通文本替换和表格处理之后
|
||||
foreach (var p in doc.Paragraphs)
|
||||
{
|
||||
var li = GetListInfo(p, data);
|
||||
if (li.IsList)
|
||||
{
|
||||
var pc = li.PTemp;
|
||||
for (int i = 0; i < li.Data.Count; i++)
|
||||
{
|
||||
var pt = pc.InsertParagraphAfterSelf(p);
|
||||
if (li.IsDict)
|
||||
{
|
||||
pc = ReplaceParagraph(pt, (Dictionary<string, object>)li.Data[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = ReplaceParagraph(pt, li.Data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//删除模板行
|
||||
li.PTemp.Remove(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//do nonthing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReplaceTable(DocX doc, Dictionary<string, object> data)
|
||||
{
|
||||
var tbs = doc.Tables;
|
||||
foreach (var table in tbs)
|
||||
{
|
||||
//需要先判断表格是列表还是表单
|
||||
var ti = GetTableInfo(table, data);
|
||||
if (ti.IsList)
|
||||
{
|
||||
for (int i = 0; i < ti.Data.Count; i++)
|
||||
{
|
||||
var rt = table.InsertRow(ti.RowTemp);
|
||||
rt.Height = ti.RowTemp.Height;
|
||||
rt.MinHeight = ti.RowTemp.MinHeight;
|
||||
if (ti.IsDict)
|
||||
{
|
||||
ReplaceRow(rt, (Dictionary<string, object>)ti.Data[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceRow(rt, ti.Data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//删除模板行
|
||||
ti.RowTemp.Remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
//do nonthing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReplaceRow(Row row, Dictionary<string, object> data)
|
||||
{
|
||||
foreach (var cell in row.Cells)
|
||||
{
|
||||
foreach (var item in cell.Paragraphs)
|
||||
{
|
||||
ReplaceParagraph(item, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReplaceRow(Row row, object data)
|
||||
{
|
||||
foreach (var cell in row.Cells)
|
||||
{
|
||||
foreach (var item in cell.Paragraphs)
|
||||
{
|
||||
ReplaceParagraph(item, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Paragraph ReplaceParagraph(Paragraph p, Dictionary<string, object> data)
|
||||
{
|
||||
Paragraph pr = p;
|
||||
var ms = GetMatches(p.Text);
|
||||
var ks = new List<string>();
|
||||
var rs = new List<string>();
|
||||
foreach (Match m in ms)
|
||||
{
|
||||
if (m.Groups.Count > 1)
|
||||
{
|
||||
string text = m.Groups[1].Value;
|
||||
if (text.Contains("."))
|
||||
{
|
||||
var ts = text.Split(".");
|
||||
text = ts[ts.Length - 1];
|
||||
}
|
||||
|
||||
ks.Add(text);
|
||||
rs.Add(m.Value);
|
||||
}
|
||||
}
|
||||
|
||||
bool isCt = data.Any(op => ks.Any(o => o.Contains(op.Key)));
|
||||
bool isReplace = false;
|
||||
|
||||
if (isCt)
|
||||
{
|
||||
if (ks.Count > 1)
|
||||
{
|
||||
for (int i = 0; i < ks.Count; i++)
|
||||
{
|
||||
if (data.ContainsKey(ks[i]))
|
||||
{
|
||||
p.ReplaceText(rs[i], data[ks[i]]?.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ks.Count == 1)
|
||||
{
|
||||
string text = ks[0];
|
||||
if (data.ContainsKey(text))
|
||||
{
|
||||
var ct = data[text]?.ToString();
|
||||
var cts = ResolveText(ct);
|
||||
var pc = p;
|
||||
foreach (var item2 in cts)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item2)) continue;
|
||||
var pt = pc.InsertParagraphAfterSelf(p);
|
||||
pt.ReplaceText(rs[0], item2);
|
||||
pc = pt;
|
||||
pr = pc;
|
||||
}
|
||||
|
||||
isReplace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isReplace)
|
||||
{
|
||||
//删除原来段落
|
||||
p.Remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
private static Paragraph ReplaceParagraph(Paragraph p, object data)
|
||||
{
|
||||
var ms = GetMatches(p.Text);
|
||||
var isReplace = false;
|
||||
Paragraph pr = p;
|
||||
foreach (Match item1 in ms)
|
||||
{
|
||||
if (item1.Groups.Count > 1)
|
||||
{
|
||||
string text = item1.Groups[1].Value;
|
||||
|
||||
var ct = data?.ToString();
|
||||
var cts = ResolveText(ct);
|
||||
var pc = p;
|
||||
foreach (var item2 in cts)
|
||||
{
|
||||
var pt = pc.InsertParagraphAfterSelf(p);
|
||||
pt.ReplaceText(item1.Value, item2);
|
||||
pc = pt;
|
||||
pr = pc;
|
||||
}
|
||||
|
||||
isReplace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isReplace)
|
||||
{
|
||||
//删除原来段落
|
||||
p.Remove(false);
|
||||
}
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
private static IList<string> ResolveText(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return new List<string>();
|
||||
text = text.Replace("\r\n", "\n").Replace("\r", "\n");
|
||||
return text.Split('\n');
|
||||
}
|
||||
|
||||
private static MatchCollection GetMatches(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) text = "";
|
||||
Regex regex = new Regex("[#|\\$]([a-zA-Z0-9_.]+?)[#|\\$]",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
return regex.Matches(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 只获取列表匹配项
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
private static MatchCollection GetListMatches(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) text = "";
|
||||
Regex regex = new Regex("\\$([a-zA-Z0-9_.]+?)\\$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
return regex.Matches(text);
|
||||
}
|
||||
|
||||
//纯辅助方法
|
||||
private class TableInfo
|
||||
{
|
||||
public bool IsList { get; set; }
|
||||
public bool IsDict { get; set; }
|
||||
public Row RowTemp { get; set; }
|
||||
public IList<object> Data { get; set; }
|
||||
}
|
||||
|
||||
//判断表格是列表还是表单
|
||||
private static TableInfo GetTableInfo(Table table, Dictionary<string, object> data)
|
||||
{
|
||||
TableInfo result = new TableInfo();
|
||||
var r0 = table.Rows[table.Rows.Count - 1];
|
||||
var c0 = r0.Cells[r0.Cells.Count - 1];
|
||||
var ct = c0.Paragraphs[0].Text;
|
||||
var ms = GetListMatches(ct);
|
||||
foreach (Match item in ms)
|
||||
{
|
||||
if (item.Groups.Count > 1)
|
||||
{
|
||||
string text = item.Groups[1].Value;
|
||||
if (text.Contains("."))
|
||||
{
|
||||
result.IsDict = true;
|
||||
text = text.Split('.')[0];
|
||||
}
|
||||
|
||||
if (data.ContainsKey(text) && (data[text] is IList)) //判断是否是列表
|
||||
{
|
||||
result.RowTemp = r0;
|
||||
result.IsList = true;
|
||||
result.Data = new List<object>();
|
||||
foreach (var item1 in (data[text] as IList))
|
||||
{
|
||||
result.Data.Add(item1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class ListInfo
|
||||
{
|
||||
public bool IsList { get; set; }
|
||||
public bool IsDict { get; set; }
|
||||
public Paragraph PTemp { get; set; }
|
||||
public IList<object> Data { get; set; }
|
||||
}
|
||||
|
||||
private static ListInfo GetListInfo(Paragraph p, Dictionary<string, object> data)
|
||||
{
|
||||
ListInfo result = new ListInfo();
|
||||
var ms = GetListMatches(p.Text);
|
||||
foreach (Match item in ms)
|
||||
{
|
||||
if (item.Groups.Count > 1)
|
||||
{
|
||||
string text = item.Groups[1].Value;
|
||||
if (text.Contains("."))
|
||||
{
|
||||
result.IsDict = true;
|
||||
text = text.Split('.')[0];
|
||||
}
|
||||
|
||||
if (data.ContainsKey(text) && (data[text] is IList)) //判断是否是列表
|
||||
{
|
||||
result.PTemp = p;
|
||||
result.IsList = true;
|
||||
result.Data = new List<object>();
|
||||
foreach (var item1 in (data[text] as IList))
|
||||
{
|
||||
result.Data.Add(item1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,710 @@
|
|||
using System.Xml;
|
||||
|
||||
namespace Infrastructure.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// XMLHelper参数
|
||||
/// </summary>
|
||||
public class XmlParameter
|
||||
{
|
||||
private string _name;
|
||||
private string _innerText;
|
||||
private string _namespaceOfPrefix;
|
||||
private AttributeParameter[] _attributes;
|
||||
|
||||
public XmlParameter() { }
|
||||
public XmlParameter(string name, params AttributeParameter[] attParas) : this(name, null, null, attParas) { }
|
||||
public XmlParameter(string name, string innerText, params AttributeParameter[] attParas) : this(name, innerText, null, attParas) { }
|
||||
public XmlParameter(string name, string innerText, string namespaceOfPrefix, params AttributeParameter[] attParas)
|
||||
{
|
||||
this._name = name;
|
||||
this._innerText = innerText;
|
||||
this._namespaceOfPrefix = namespaceOfPrefix;
|
||||
this._attributes = attParas;
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点名称
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return this._name; }
|
||||
set { this._name = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点文本
|
||||
/// </summary>
|
||||
public string InnerText
|
||||
{
|
||||
get { return this._innerText; }
|
||||
set { this._innerText = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点前缀xmlns声明(命名空间URI)
|
||||
/// </summary>
|
||||
public string NamespaceOfPrefix
|
||||
{
|
||||
get { return this._namespaceOfPrefix; }
|
||||
set { this._namespaceOfPrefix = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 节点属性集
|
||||
/// </summary>
|
||||
public AttributeParameter[] Attributes
|
||||
{
|
||||
get { return this._attributes; }
|
||||
set { this._attributes = value; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点属性参数
|
||||
/// </summary>
|
||||
public class AttributeParameter
|
||||
{
|
||||
private string _name;
|
||||
private string _value;
|
||||
|
||||
public AttributeParameter() { }
|
||||
public AttributeParameter(string attributeName, string attributeValue)
|
||||
{
|
||||
this._name = attributeName;
|
||||
this._value = attributeValue;
|
||||
}
|
||||
/// <summary>
|
||||
/// 属性名称
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return this._name; }
|
||||
set { this._name = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 属性值
|
||||
/// </summary>
|
||||
public string Value
|
||||
{
|
||||
get { return this._value; }
|
||||
set { this._value = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class XMLHelper
|
||||
{
|
||||
private static string _xPath;
|
||||
/// <summary>
|
||||
/// xml文件路径
|
||||
/// </summary>
|
||||
public static string XmlPath
|
||||
{
|
||||
get { return _xPath; }
|
||||
set { _xPath = value; }
|
||||
}
|
||||
private static string _configName = "XmlPath";
|
||||
/// <summary>
|
||||
/// 配置文件节点名称,请设置在AppSettings节点下
|
||||
/// </summary>
|
||||
public static string ConfigName
|
||||
{
|
||||
get { return _configName; }
|
||||
set { _configName = value; GetConfig(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 从配置文件读取xml路径
|
||||
/// </summary>
|
||||
static void GetConfig()
|
||||
{
|
||||
//if (string.IsNullOrEmpty(_xPath))
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// _xPath = ConfigurationManager.AppSettings[_configName];
|
||||
// }
|
||||
// catch { }
|
||||
//}
|
||||
}
|
||||
static XMLHelper() { GetConfig(); }
|
||||
|
||||
#region private AppendChild
|
||||
/// <summary>
|
||||
/// 添加一个子节点
|
||||
/// </summary>
|
||||
/// <param name="xDoc">XmlDocument对象</param>
|
||||
/// <param name="parentNode">父节点</param>
|
||||
/// <param name="xlParameter">Xml参数</param>
|
||||
private static void AppendChild(XmlDocument xDoc, XmlNode parentNode, params XmlParameter[] xlParameter)
|
||||
{
|
||||
foreach (XmlParameter xpar in xlParameter)
|
||||
{
|
||||
XmlNode newNode = xDoc.CreateNode(XmlNodeType.Element, xpar.Name, null);
|
||||
string ns = string.IsNullOrEmpty(xpar.NamespaceOfPrefix) ? "" : newNode.GetNamespaceOfPrefix(xpar.NamespaceOfPrefix);
|
||||
foreach (AttributeParameter attp in xpar.Attributes)
|
||||
{
|
||||
XmlNode attr = xDoc.CreateNode(XmlNodeType.Attribute, attp.Name, ns == "" ? null : ns);
|
||||
attr.Value = attp.Value;
|
||||
newNode.Attributes.SetNamedItem(attr);
|
||||
}
|
||||
newNode.InnerText = xpar.InnerText;
|
||||
parentNode.AppendChild(newNode);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region private AddEveryNode
|
||||
private static void AddEveryNode(XmlDocument xDoc, XmlNode parentNode, params XmlParameter[] paras)
|
||||
{
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
foreach (XmlNode xns in nlst)
|
||||
{
|
||||
if (xns.Name == parentNode.Name)
|
||||
{
|
||||
AppendChild(xDoc, xns, paras);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (XmlNode xn in xns)
|
||||
{
|
||||
if (xn.Name == parentNode.Name)
|
||||
{
|
||||
AppendChild(xDoc, xn, paras);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region private GetXmlDom
|
||||
/// <summary>
|
||||
/// 获得一个XmlDocument对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static XmlDocument GetXmlDom()
|
||||
{
|
||||
XmlDocument xdoc = new XmlDocument();
|
||||
xdoc.Load(_xPath);
|
||||
return xdoc;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CreateXmlFile
|
||||
/// <summary>
|
||||
/// 创建一个XML文档,成功创建后操作路径将直接指向该文件
|
||||
/// </summary>
|
||||
/// <param name="fileName">文件物理路径名</param>
|
||||
/// <param name="rootNode">根结点名称</param>
|
||||
/// <param name="elementName">元素节点名称</param>
|
||||
/// <param name="xmlParameter">XML参数</param>
|
||||
public static void CreateXmlFile(string fileName, string rootNode, string elementName, params XmlParameter[] xmlParameter)
|
||||
{
|
||||
XmlDocument xDoc = new XmlDocument();
|
||||
XmlNode xn = xDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
xDoc.AppendChild(xn);
|
||||
XmlNode root = xDoc.CreateElement(rootNode);
|
||||
xDoc.AppendChild(root);
|
||||
XmlNode ln = xDoc.CreateNode(XmlNodeType.Element, elementName, null);
|
||||
AppendChild(xDoc, ln, xmlParameter);
|
||||
root.AppendChild(ln);
|
||||
try
|
||||
{
|
||||
xDoc.Save(fileName);
|
||||
_xPath = fileName;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建一个XML文档,成功创建后操作路径将直接指向该文件
|
||||
/// </summary>
|
||||
/// <param name="fileName">文件物理路径名</param>
|
||||
/// <param name="xmlString">xml字符串</param>
|
||||
public static void CreateXmlFile(string fileName, string xmlString)
|
||||
{
|
||||
XmlDocument xDoc = new XmlDocument();
|
||||
try
|
||||
{
|
||||
xDoc.LoadXml(xmlString);
|
||||
xDoc.Save(fileName);
|
||||
_xPath = fileName;
|
||||
}
|
||||
catch { throw; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AddNewNode
|
||||
/// <summary>
|
||||
/// 添加新节点
|
||||
/// </summary>
|
||||
/// <param name="parentNode">新节点的父节点对象</param>
|
||||
/// <param name="xmlParameter">Xml参数对象</param>
|
||||
public static void AddNewNode(XmlNode parentNode, params XmlParameter[] xmlParameter)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
if (parentNode.Name == xDoc.DocumentElement.Name)
|
||||
{
|
||||
XmlNode newNode = xDoc.CreateNode(XmlNodeType.Element, xDoc.DocumentElement.ChildNodes[0].Name, null);
|
||||
AppendChild(xDoc, newNode, xmlParameter);
|
||||
xDoc.DocumentElement.AppendChild(newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddEveryNode(xDoc, parentNode, xmlParameter);
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加新节点
|
||||
/// </summary>
|
||||
/// <param name="xDoc">XmlDocument对象</param>
|
||||
/// <param name="parentName">新节点的父节点名称</param>
|
||||
/// <param name="xmlParameter">XML参数对象</param>
|
||||
public static void AddNewNode(string parentName, params XmlParameter[] xmlParameter)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNode parentNode = GetNode(xDoc, parentName);
|
||||
if (parentNode == null) return;
|
||||
if (parentNode.Name == xDoc.DocumentElement.Name)
|
||||
{
|
||||
XmlNode newNode = xDoc.CreateNode(XmlNodeType.Element, xDoc.DocumentElement.ChildNodes[0].Name, null);
|
||||
AppendChild(xDoc, newNode, xmlParameter);
|
||||
xDoc.DocumentElement.AppendChild(newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddEveryNode(xDoc, parentNode, xmlParameter);
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AddAttribute
|
||||
/// <summary>
|
||||
/// 添加节点属性
|
||||
/// </summary>
|
||||
/// <param name="node">节点对象</param>
|
||||
/// <param name="namespaceOfPrefix">该节点的命名空间URI</param>
|
||||
/// <param name="attributeName">新属性名称</param>
|
||||
/// <param name="attributeValue">属性值</param>
|
||||
public static void AddAttribute(XmlNode node, string namespaceOfPrefix, string attributeName, string attributeValue)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
string ns = string.IsNullOrEmpty(namespaceOfPrefix) ? "" : node.GetNamespaceOfPrefix(namespaceOfPrefix);
|
||||
XmlNode xn = xDoc.CreateNode(XmlNodeType.Attribute, attributeName, ns == "" ? null : ns);
|
||||
xn.Value = attributeValue;
|
||||
node.Attributes.SetNamedItem(xn);
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加节点属性
|
||||
/// </summary>
|
||||
/// <param name="node">节点对象</param>
|
||||
/// <param name="namespaceOfPrefix">该节点的命名空间URI</param>
|
||||
/// <param name="attributeParameters">节点属性参数</param>
|
||||
public static void AddAttribute(XmlNode node, string namespaceOfPrefix, params AttributeParameter[] attributeParameters)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
string ns = string.IsNullOrEmpty(namespaceOfPrefix) ? "" : node.GetNamespaceOfPrefix(namespaceOfPrefix);
|
||||
foreach (AttributeParameter attp in attributeParameters)
|
||||
{
|
||||
XmlNode xn = xDoc.CreateNode(XmlNodeType.Attribute, attp.Name, ns == "" ? null : ns);
|
||||
xn.Value = attp.Value;
|
||||
node.Attributes.SetNamedItem(xn);
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加节点属性
|
||||
/// </summary>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <param name="namespaceOfPrefix">该节点的命名空间URI</param>
|
||||
/// <param name="attributeName">新属性名称</param>
|
||||
/// <param name="attributeValue">属性值</param>
|
||||
public static void AddAttribute(string nodeName, string namespaceOfPrefix, string attributeName, string attributeValue)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList xlst = xDoc.DocumentElement.ChildNodes;
|
||||
for (int i = 0; i < xlst.Count; i++)
|
||||
{
|
||||
XmlNode node = GetNode(xlst[i], nodeName);
|
||||
if (node == null) break;
|
||||
AddAttribute(node, namespaceOfPrefix, attributeName, attributeValue);
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加节点属性
|
||||
/// </summary>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <param name="namespaceOfPrefix">该节点的命名空间URI</param>
|
||||
/// <param name="attributeParameters">节点属性参数</param>
|
||||
public static void AddAttribute(string nodeName, string namespaceOfPrefix, params AttributeParameter[] attributeParameters)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList xlst = xDoc.DocumentElement.ChildNodes;
|
||||
for (int i = 0; i < xlst.Count; i++)
|
||||
{
|
||||
XmlNode node = GetNode(xlst[i], nodeName);
|
||||
if (node == null) break;
|
||||
AddAttribute(node, namespaceOfPrefix, attributeParameters);
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetNode
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <returns></returns>
|
||||
public static XmlNode GetNode(string nodeName)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
if (xDoc.DocumentElement.Name == nodeName) return (XmlNode)xDoc.DocumentElement;
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
foreach (XmlNode xns in nlst) // 遍历所有子节点
|
||||
{
|
||||
if (xns.Name == nodeName) return xns;
|
||||
else
|
||||
{
|
||||
XmlNode xn = GetNode(xns, nodeName);
|
||||
if (xn != null) return xn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="node">节点对象</param>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <returns></returns>
|
||||
public static XmlNode GetNode(XmlNode node, string nodeName)
|
||||
{
|
||||
foreach (XmlNode xn in node)
|
||||
{
|
||||
if (xn.Name == nodeName) return xn;
|
||||
else
|
||||
{
|
||||
XmlNode tmp = GetNode(xn, nodeName);
|
||||
if (tmp != null) return tmp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="index">节点索引</param>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
public static XmlNode GetNode(int index, string nodeName)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
if (nlst.Count <= index) return null;
|
||||
if (nlst[index].Name == nodeName) return (XmlNode)nlst[index];
|
||||
foreach (XmlNode xn in nlst[index])
|
||||
{
|
||||
return GetNode(xn, nodeName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="node">节点对象</param>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <param name="innerText">节点内容</param>
|
||||
public static XmlNode GetNode(XmlNode node, string nodeName, string innerText)
|
||||
{
|
||||
foreach (XmlNode xn in node)
|
||||
{
|
||||
if (xn.Name == nodeName && xn.InnerText == innerText) return xn;
|
||||
else
|
||||
{
|
||||
XmlNode tmp = GetNode(xn, nodeName, innerText);
|
||||
if (tmp != null) return tmp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <param name="innerText">节点内容</param>
|
||||
public static XmlNode GetNode(string nodeName, string innerText)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
foreach (XmlNode xns in nlst) // 遍历所有子节点
|
||||
{
|
||||
if (xns.Name == nodeName && xns.InnerText == innerText) return xns;
|
||||
XmlNode tmp = GetNode(xns, nodeName, innerText);
|
||||
if (tmp != null) return tmp;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="xmlParameter">XML参数</param>
|
||||
public static XmlNode GetNode(XmlParameter xmlParameter)
|
||||
{
|
||||
return GetNode(xmlParameter.Name, xmlParameter.InnerText);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定节点名称的节点对象
|
||||
/// </summary>
|
||||
/// <param name="node">节点对象</param>
|
||||
/// <param name="xmlParameter">XML参数</param>
|
||||
public static XmlNode GetNode(XmlNode node, XmlParameter xmlParameter)
|
||||
{
|
||||
return GetNode(node, xmlParameter.Name, node.InnerText);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UpdateNode
|
||||
private static void UpdateNode(XmlNode node, XmlParameter xmlParameter)
|
||||
{
|
||||
node.InnerText = xmlParameter.InnerText;
|
||||
for (int i = 0; i < xmlParameter.Attributes.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < node.Attributes.Count; j++)
|
||||
{
|
||||
if (node.Attributes[j].Name == xmlParameter.Attributes[i].Name)
|
||||
{
|
||||
node.Attributes[j].Value = xmlParameter.Attributes[i].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void UpdateNode(XmlNode node, string innerText, AttributeParameter[] attributeParameters)
|
||||
{
|
||||
node.InnerText = innerText;
|
||||
for (int i = 0; i < attributeParameters.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < node.Attributes.Count; j++)
|
||||
{
|
||||
if (node.Attributes[j].Name == attributeParameters[i].Name)
|
||||
{
|
||||
node.Attributes[j].Value = attributeParameters[i].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改节点的内容
|
||||
/// </summary>
|
||||
/// <param name="index">节点索引</param>
|
||||
/// <param name="xmlParameter">XML参数对象</param>
|
||||
public static void UpdateNode(int index, XmlParameter xmlParameter)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
if (nlst.Count <= index) return;
|
||||
if (nlst[index].Name == xmlParameter.Name)
|
||||
{
|
||||
UpdateNode(nlst[index], xmlParameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (XmlNode xn in nlst[index])
|
||||
{
|
||||
XmlNode xnd = GetNode(xn, xmlParameter.Name);
|
||||
if (xnd != null)
|
||||
{
|
||||
UpdateNode(xnd, xmlParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改节点的内容
|
||||
/// </summary>
|
||||
/// <param name="index">节点索引</param>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <param name="newInnerText">修改后的内容</param>
|
||||
public static void UpdateNode(int index, string nodeName, string newInnerText)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
if (nlst.Count <= index) return;
|
||||
if (nlst[index].Name == nodeName)
|
||||
{
|
||||
nlst[index].InnerText = newInnerText;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (XmlNode xn in nlst[index])
|
||||
{
|
||||
XmlNode xnd = GetNode(xn, nodeName);
|
||||
if (xnd != null)
|
||||
{
|
||||
xnd.InnerText = newInnerText;
|
||||
}
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改节点的内容
|
||||
/// </summary>
|
||||
/// <param name="xmlParameter">XmlParameter对象</param>
|
||||
/// <param name="innerText">修改后的内容</param>
|
||||
/// <param name="attributeParameters">需要修改的属性</param>
|
||||
public static void UpdateNode(XmlParameter xmlParameter, string innerText, params AttributeParameter[] attributeParameters)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
foreach (XmlNode xns in nlst) // 遍历所有子节点
|
||||
{
|
||||
if (xns.Name == xmlParameter.Name && xns.InnerText == xmlParameter.InnerText)
|
||||
{
|
||||
UpdateNode(xns, innerText, attributeParameters);
|
||||
break;
|
||||
}
|
||||
XmlNode tmp = GetNode(xns, xmlParameter);
|
||||
if (tmp != null)
|
||||
{
|
||||
UpdateNode(tmp, innerText, attributeParameters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DeleteNode
|
||||
/// <summary>
|
||||
/// 删除节点
|
||||
/// </summary>
|
||||
/// <param name="index">节点索引</param>
|
||||
public static void DeleteNode(int index)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
nlst[index].ParentNode.RemoveChild(nlst[index]);
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除节点
|
||||
/// </summary>
|
||||
/// <param name="nodeList">需要删除的节点对象</param>
|
||||
public static void DeleteNode(params XmlNode[] nodeList)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
foreach (XmlNode xnl in nodeList)
|
||||
{
|
||||
foreach (XmlNode xn in xDoc.DocumentElement.ChildNodes)
|
||||
{
|
||||
if (xnl.Equals(xn))
|
||||
{
|
||||
xn.ParentNode.RemoveChild(xn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除节点
|
||||
/// </summary>
|
||||
/// <param name="xDoc">XmlDocument对象</param>
|
||||
/// <param name="nodeName">节点名称</param>
|
||||
/// <param name="nodeText">节点内容</param>
|
||||
public static void DeleteNode(string nodeName, string nodeText)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
foreach (XmlNode xn in xDoc.DocumentElement.ChildNodes)
|
||||
{
|
||||
if (xn.Name == nodeName)
|
||||
{
|
||||
if (xn.InnerText == nodeText)
|
||||
{
|
||||
xn.ParentNode.RemoveChild(xn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlNode node = GetNode(xn, nodeName);
|
||||
if (node != null && node.InnerText == nodeText)
|
||||
{
|
||||
node.ParentNode.ParentNode.RemoveChild(node.ParentNode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetAttribute
|
||||
/// <summary>
|
||||
/// 修改属性值
|
||||
/// </summary>
|
||||
/// <param name="elem">元素对象</param>
|
||||
/// <param name="attps">属性参数</param>
|
||||
private static void SetAttribute(XmlElement elem, params AttributeParameter[] attps)
|
||||
{
|
||||
foreach (AttributeParameter attp in attps)
|
||||
{
|
||||
elem.SetAttribute(attp.Name, attp.Value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改属性值
|
||||
/// </summary>
|
||||
/// <param name="xmlParameter">XML参数</param>
|
||||
/// <param name="attributeParameters">属性参数</param>
|
||||
public static void SetAttribute(XmlParameter xmlParameter, params AttributeParameter[] attributeParameters)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
foreach (XmlNode xns in nlst) // 遍历所有子节点
|
||||
{
|
||||
if (xns.Name == xmlParameter.Name && xns.InnerText == xmlParameter.InnerText)
|
||||
{
|
||||
SetAttribute((XmlElement)xns, attributeParameters);
|
||||
break;
|
||||
}
|
||||
XmlNode tmp = GetNode(xns, xmlParameter);
|
||||
if (tmp != null)
|
||||
{
|
||||
SetAttribute((XmlElement)tmp, attributeParameters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改属性值
|
||||
/// </summary>
|
||||
/// <param name="xmlParameter">XML参数</param>
|
||||
/// <param name="attributeValue">新属性值</param>
|
||||
public static void SetAttribute(XmlParameter xmlParameter, string attributeName, string attributeValue)
|
||||
{
|
||||
XmlDocument xDoc = GetXmlDom();
|
||||
XmlNodeList nlst = xDoc.DocumentElement.ChildNodes;
|
||||
foreach (XmlNode xns in nlst) // 遍历所有子节点
|
||||
{
|
||||
if (xns.Name == xmlParameter.Name && xns.InnerText == xmlParameter.InnerText)
|
||||
{
|
||||
((XmlElement)xns).SetAttribute(attributeName, attributeValue);
|
||||
break;
|
||||
}
|
||||
XmlNode tmp = GetNode(xns, xmlParameter);
|
||||
if (tmp != null)
|
||||
{
|
||||
((XmlElement)tmp).SetAttribute(attributeName, attributeValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xDoc.Save(_xPath);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net5.0\Infrastructure.xml</DocumentationFile>
|
||||
<NoWarn>1701;1702;1591;1573;1572;1570</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="12.0.1" />
|
||||
<PackageReference Include="DocXCore.Standard" Version="1.0.1" />
|
||||
<PackageReference Include="EnyimMemcachedCore" Version="2.6.4" />
|
||||
<PackageReference Include="log4net" Version="2.0.15" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||
<PackageReference Include="NetTopologySuite" Version="2.5.0" />
|
||||
<PackageReference Include="NetTopologySuite.IO.Esri.Shapefile" Version="1.0.0" />
|
||||
<PackageReference Include="NetTopologySuite.IO.ShapeFile" Version="2.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="NPOI" Version="2.5.6" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Include="PinYinConverterCore" Version="1.0.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.6.111" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="log4net.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// Json操作
|
||||
/// </summary>
|
||||
public static class Json
|
||||
{
|
||||
public static object ToJson(this string Json)
|
||||
{
|
||||
return Json == null ? null : JsonConvert.DeserializeObject(Json);
|
||||
}
|
||||
public static string ToJson(this object obj)
|
||||
{
|
||||
var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
|
||||
return JsonConvert.SerializeObject(obj, timeConverter);
|
||||
}
|
||||
public static string ToJson(this object obj, string datetimeformats)
|
||||
{
|
||||
var timeConverter = new IsoDateTimeConverter { DateTimeFormat = datetimeformats };
|
||||
return JsonConvert.SerializeObject(obj, timeConverter);
|
||||
}
|
||||
public static T ToObject<T>(this string Json)
|
||||
{
|
||||
return Json == null ? default(T) : JsonConvert.DeserializeObject<T>(Json);
|
||||
}
|
||||
public static List<T> ToList<T>(this string Json)
|
||||
{
|
||||
return Json == null ? null : JsonConvert.DeserializeObject<List<T>>(Json);
|
||||
}
|
||||
public static DataTable ToTable(this string Json)
|
||||
{
|
||||
return Json == null ? null : JsonConvert.DeserializeObject<DataTable>(Json);
|
||||
}
|
||||
public static JObject ToJObject(this string Json)
|
||||
{
|
||||
return Json == null ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", ""));
|
||||
}
|
||||
/// <summary>
|
||||
/// 转换成JToken
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static JToken ToJToken(this string str)
|
||||
{
|
||||
try
|
||||
{
|
||||
var jToken = (JToken)JsonConvert.DeserializeObject(str);
|
||||
return jToken;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查请求参数是否异常
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public static void CheckReqIsNull(this object obj)
|
||||
{
|
||||
if (obj == null) throw new Exception("数据异常,请检查输入信息是否正确。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public static List<T> InitListData<T>(this List<T> list)
|
||||
{
|
||||
if (list == null) list = new List<T>();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : Infrastructure
|
||||
// Author : Yubao Li
|
||||
// Created : 09-07-2015
|
||||
//
|
||||
// Last Modified By : Yubao Li
|
||||
// Last Modified On : 09-07-2015
|
||||
// ***********************************************************************
|
||||
// <copyright file="GuidConverter.cs" company="">
|
||||
// Copyright (c) . All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>解决JSON转换空GUID问题</summary>
|
||||
// ***********************************************************************
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public class GuidConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType.IsAssignableFrom(typeof(Guid));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
Guid result = Guid.Empty;
|
||||
if (reader.Value == null) return result;
|
||||
Guid.TryParse(reader.Value.ToString(), out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class DecimalConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType.IsAssignableFrom(typeof(decimal));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
decimal result = 0;
|
||||
if (reader.Value == null) return result;
|
||||
decimal.TryParse(reader.Value.ToString(), out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// ***********************************************************************
|
||||
// Assembly : FairUtility
|
||||
// Author : Yubao Li
|
||||
// Created : 08-12-2015
|
||||
//
|
||||
// Last Modified By : Yubao Li
|
||||
// Last Modified On : 08-12-2015
|
||||
// ***********************************************************************
|
||||
// <copyright file="JsonHelper.cs" company="">
|
||||
// Copyright (c) . All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>json序列化帮助类</summary>
|
||||
// ***********************************************************************
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public class JsonHelper
|
||||
{
|
||||
private static JsonHelper _jsonHelper = new JsonHelper();
|
||||
public static JsonHelper Instance { get { return _jsonHelper; } }
|
||||
|
||||
public string Serialize(object obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
|
||||
}
|
||||
|
||||
public string SerializeByConverter(object obj, params JsonConverter[] converters)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, converters);
|
||||
}
|
||||
|
||||
public T Deserialize<T>(string input)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(input);
|
||||
}
|
||||
|
||||
public T DeserializeByConverter<T>(string input,params JsonConverter[] converter)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(input, converter);
|
||||
}
|
||||
|
||||
public T DeserializeBySetting<T>(string input, JsonSerializerSettings settings)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(input, settings);
|
||||
}
|
||||
|
||||
private object NullToEmpty(object obj)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace Infrastructure
|
||||
{
|
||||
public class KeyDescription
|
||||
{
|
||||
/// <summary>
|
||||
/// 键值
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
/// <summary>
|
||||
/// 键的描述
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端是否显示
|
||||
/// </summary>
|
||||
public bool Browsable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段类型
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Infrastructure.Middleware
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class ApplicationBuilderExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 注入日志中间件
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseLogMiddleware(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<RequestResponseLoggingMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Infrastructure.Middleware
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求与返回中间件
|
||||
/// </summary>
|
||||
public class RequestResponseLoggingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<RequestResponseLoggingMiddleware> _log;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RequestResponseLoggingMiddleware(RequestDelegate next, ILogger<RequestResponseLoggingMiddleware> log)
|
||||
{
|
||||
_next = next;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
#region 这里可以加入正则验证context.Path。 过滤不需要记录日志的api
|
||||
|
||||
//var path = context.Request.Path.ToString().ToLower();
|
||||
|
||||
//if (path.Contains("/index") || path.Contains("/check") ||
|
||||
// path.Contains("/swagger") || path.Contains("/getsysdatas") || path.Contains("/load"))
|
||||
//{
|
||||
await CatchNext(context);
|
||||
// return;
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 日志
|
||||
// 启用耗时 日志记录
|
||||
//var stopwatch = new Stopwatch();
|
||||
//stopwatch.Start();
|
||||
//var logData = new Dictionary<string, object>();
|
||||
//var request = context.Request;
|
||||
//logData.Add("request.url", request.Path.ToString());
|
||||
//logData.Add("request.headers",
|
||||
// request.Headers.ToDictionary(x => x.Key, v => string.Join(";", v.Value.ToList())));
|
||||
//logData.Add("request.method", request.Method);
|
||||
//logData.Add("request.executeStartTime", DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
////追踪实别器
|
||||
//logData.Add("traceIdentifier", context.TraceIdentifier);
|
||||
//// 获取请求body内容
|
||||
//if (request.Method.ToLower().Equals("post"))
|
||||
//{
|
||||
// // 启用倒带功能,就可以让 Request.Body 可以再次读取
|
||||
// request.EnableBuffering();
|
||||
// // 文件上传 记录文件信息
|
||||
// if (path.Contains("/upload"))
|
||||
// {
|
||||
// var content = string.Join(",", request.Form.Files.Select(item => item.FileName));
|
||||
// logData.Add("request.body", $"收到上传文件:{content}");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var sr = new StreamReader(request.Body, Encoding.UTF8);
|
||||
// var content = sr.ReadToEndAsync().Result;
|
||||
// logData.Add("request.body", content);
|
||||
// request.Body.Position = 0;
|
||||
// }
|
||||
//}
|
||||
//else if (request.Method.ToLower().Equals("get"))
|
||||
//{
|
||||
// logData.Add("request.body", request.QueryString.Value);
|
||||
//}
|
||||
|
||||
//// 获取Response.Body内容
|
||||
//var originalBodyStream = context.Response.Body;
|
||||
//using (var responseBody = new MemoryStream())
|
||||
//{
|
||||
// context.Response.Body = responseBody;
|
||||
// await CatchNext(context);
|
||||
// if (!logData.ContainsKey("response.body"))
|
||||
// {
|
||||
// logData.Add("response.body", await GetResponse(context.Response));
|
||||
// }
|
||||
|
||||
// logData.Add("response.executeEndTime", DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
// logData.Add("response.statusCode", context.Response.StatusCode);
|
||||
// await responseBody.CopyToAsync(originalBodyStream);
|
||||
//}
|
||||
|
||||
//// 响应完成记录时间和存入日志
|
||||
//context.Response.OnCompleted(() =>
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// stopwatch.Stop();
|
||||
// logData.Add("elapsedTime", stopwatch.ElapsedMilliseconds + "ms");
|
||||
// var json = JsonHelper.Instance.Serialize(logData);
|
||||
// _log.LogInformation(json);
|
||||
// return Task.CompletedTask;
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// return Task.FromException(ex);
|
||||
// }
|
||||
//});
|
||||
#endregion
|
||||
}
|
||||
|
||||
private async Task CatchNext(HttpContext context)
|
||||
{
|
||||
var logData = new Dictionary<string, object>();
|
||||
try
|
||||
{
|
||||
var request = context.Request;
|
||||
request.EnableBuffering();
|
||||
|
||||
// 获取请求body内容
|
||||
if (request.Method.ToLower().Equals("post"))
|
||||
{
|
||||
// 启用倒带功能,就可以让 Request.Body 可以再次读取
|
||||
request.EnableBuffering();
|
||||
// 文件上传 记录文件信息
|
||||
var sr = new StreamReader(request.Body, Encoding.UTF8);
|
||||
var content = sr.ReadToEndAsync().Result;
|
||||
logData.Add("request.body", content);
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
else if (request.Method.ToLower().Equals("get"))
|
||||
{
|
||||
logData.Add("request.body", request.QueryString.Value);
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.LogError(JsonHelper.Instance.Serialize(logData));
|
||||
_log.LogError(ex, "系统错误日志,管道捕获");
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "application/json; charset=utf-8";
|
||||
var result = new { code = 500, message = ex.Message ?? "系统错误,请稍后再试" };
|
||||
await context.Response.WriteAsync(JsonHelper.Instance.Serialize(result));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取响应内容
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task<string> GetResponse(HttpResponse response)
|
||||
{
|
||||
response.Body.Seek(0, SeekOrigin.Begin);
|
||||
var text = await new StreamReader(response.Body).ReadToEndAsync();
|
||||
response.Body.Seek(0, SeekOrigin.Begin);
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public static class PredicateBuilder
|
||||
{
|
||||
public static Expression<Func<T, bool>> True<T>() { return f => true; }
|
||||
public static Expression<Func<T, bool>> False<T>() { return f => false; }
|
||||
|
||||
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
|
||||
Expression<Func<T, bool>> expr2)
|
||||
{
|
||||
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
|
||||
return Expression.Lambda<Func<T, bool>>
|
||||
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
|
||||
Expression<Func<T, bool>> expr2)
|
||||
{
|
||||
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
|
||||
return Expression.Lambda<Func<T, bool>>
|
||||
(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
using System.IO;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Extensions.AutofacManager;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Infrastructure.Provider
|
||||
{
|
||||
public interface IPathProvider : IDependency
|
||||
{
|
||||
string MapPath(string path);
|
||||
string MapPath(string path, bool rootPath);
|
||||
IHostEnvironment GetHostingEnvironment();
|
||||
}
|
||||
|
||||
public class PathProvider : IPathProvider
|
||||
{
|
||||
private IHostEnvironment _hostingEnvironment;
|
||||
|
||||
public PathProvider(IHostEnvironment environment)
|
||||
{
|
||||
_hostingEnvironment = environment;
|
||||
}
|
||||
public IHostEnvironment GetHostingEnvironment()
|
||||
{
|
||||
return _hostingEnvironment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取服务器文件路径
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public string MapPath(string path)
|
||||
{
|
||||
return MapPath(path, false);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取wwwroot路径
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="rootPath">是否获取wwwroot路径</param>
|
||||
/// <returns></returns>
|
||||
public string MapPath(string path, bool rootPath)
|
||||
{
|
||||
if (rootPath)
|
||||
{
|
||||
return Path.Combine(_hostingEnvironment.ContentRootPath,"wwwroot").ReplacePath();
|
||||
}
|
||||
return Path.Combine(_hostingEnvironment.ContentRootPath, path).ReplacePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
namespace Infrastructure
|
||||
{
|
||||
public class Response
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作消息【当Status不为 200时,显示详细的错误信息】
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作状态码,200为正常
|
||||
/// </summary>
|
||||
public int Code { get; set; }
|
||||
|
||||
public Response()
|
||||
{
|
||||
Code = 200;
|
||||
Message = "操作成功";
|
||||
}
|
||||
}
|
||||
|
||||
public class ResponsePage<T> : Response
|
||||
{
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class PageInfo<T>
|
||||
{
|
||||
public T Items { get; set; }
|
||||
|
||||
public int Total { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WEBAPI通用返回泛型基类
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class Response<T> : Response
|
||||
{
|
||||
/// <summary>
|
||||
/// 回传的结果
|
||||
/// </summary>
|
||||
public T Result { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
public interface IIdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成过程中产生的事件
|
||||
/// </summary>
|
||||
//Action<OverCostActionArg> GenIdActionAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成新的long型Id
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
long NewLong();
|
||||
|
||||
// Guid NewGuid();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
internal interface ISnowWorker
|
||||
{
|
||||
//Action<OverCostActionArg> GenAction { get; set; }
|
||||
|
||||
long NextId();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
public class IdGeneratorOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花计算方法
|
||||
/// (1-漂移算法|2-传统算法),默认1
|
||||
/// </summary>
|
||||
public virtual short Method { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 基础时间(UTC格式)
|
||||
/// 不能超过当前系统时间
|
||||
/// </summary>
|
||||
public virtual DateTime BaseTime { get; set; } = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// 必须由外部设定,最大值 2^WorkerIdBitLength-1
|
||||
/// </summary>
|
||||
public virtual ushort WorkerId { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码位长
|
||||
/// 默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22)
|
||||
/// </summary>
|
||||
public virtual byte WorkerIdBitLength { get; set; } = 6;//10;
|
||||
|
||||
/// <summary>
|
||||
/// 序列数位长
|
||||
/// 默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22)
|
||||
/// </summary>
|
||||
public virtual byte SeqBitLength { get; set; } = 6;//10;
|
||||
|
||||
/// <summary>
|
||||
/// 最大序列数(含)
|
||||
/// 设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1])
|
||||
/// </summary>
|
||||
public virtual int MaxSeqNumber { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最小序列数(含)
|
||||
/// 默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位
|
||||
/// </summary>
|
||||
public virtual ushort MinSeqNumber { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 最大漂移次数(含),
|
||||
/// 默认2000,推荐范围500-10000(与计算能力有关)
|
||||
/// </summary>
|
||||
public virtual int TopOverCostCount { get; set; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// 数据中心ID(默认0)
|
||||
/// </summary>
|
||||
public virtual uint DataCenterId { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 数据中心ID长度(默认0)
|
||||
/// </summary>
|
||||
public virtual byte DataCenterIdBitLength { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 时间戳类型(0-毫秒,1-秒),默认0
|
||||
/// </summary>
|
||||
public virtual byte TimestampType { get; set; } = 0;
|
||||
|
||||
|
||||
public IdGeneratorOptions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IdGeneratorOptions(ushort workerId)
|
||||
{
|
||||
WorkerId = workerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Id生成时回调参数
|
||||
/// </summary>
|
||||
public class OverCostActionArg
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// 1-开始,2-结束,8-漂移
|
||||
/// </summary>
|
||||
public virtual int ActionType { get; set; }
|
||||
/// <summary>
|
||||
/// 时间戳
|
||||
/// </summary>
|
||||
public virtual long TimeTick { get; set; }
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
public virtual ushort WorkerId { get; set; }
|
||||
/// <summary>
|
||||
/// 漂移计算次数
|
||||
/// </summary>
|
||||
public virtual int OverCostCountInOneTerm { get; set; }
|
||||
/// <summary>
|
||||
/// 漂移期间生产ID个数
|
||||
/// </summary>
|
||||
public virtual int GenCountInOneTerm { get; set; }
|
||||
/// <summary>
|
||||
/// 漂移周期
|
||||
/// </summary>
|
||||
public virtual int TermIndex { get; set; }
|
||||
|
||||
public OverCostActionArg(ushort workerId, long timeTick, int actionType = 0, int overCostCountInOneTerm = 0, int genCountWhenOverCost = 0, int index = 0)
|
||||
{
|
||||
ActionType = actionType;
|
||||
TimeTick = timeTick;
|
||||
WorkerId = workerId;
|
||||
OverCostCountInOneTerm = overCostCountInOneTerm;
|
||||
GenCountInOneTerm = genCountWhenOverCost;
|
||||
TermIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花漂移算法
|
||||
/// </summary>
|
||||
internal class SnowWorkerM1 : ISnowWorker
|
||||
{
|
||||
/// <summary>
|
||||
/// 基础时间
|
||||
/// </summary>
|
||||
protected readonly DateTime BaseTime;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
protected readonly ushort WorkerId = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码位长
|
||||
/// </summary>
|
||||
protected readonly byte WorkerIdBitLength = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 自增序列数位长
|
||||
/// </summary>
|
||||
protected readonly byte SeqBitLength = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最大序列数(含)
|
||||
/// </summary>
|
||||
protected readonly int MaxSeqNumber = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最小序列数(含)
|
||||
/// </summary>
|
||||
protected readonly ushort MinSeqNumber = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最大漂移次数(含)
|
||||
/// </summary>
|
||||
protected int TopOverCostCount = 0;
|
||||
|
||||
protected byte _TimestampShift = 0;
|
||||
protected static object _SyncLock = new object();
|
||||
|
||||
protected ushort _CurrentSeqNumber = 0;
|
||||
protected long _LastTimeTick = 0; // -1L
|
||||
protected long _TurnBackTimeTick = 0; // -1L;
|
||||
protected byte _TurnBackIndex = 0;
|
||||
protected bool _IsOverCost = false;
|
||||
protected int _OverCostCountInOneTerm = 0;
|
||||
|
||||
#if DEBUG
|
||||
protected int _GenCountInOneTerm = 0;
|
||||
protected int _TermIndex = 0;
|
||||
#endif
|
||||
|
||||
public Action<OverCostActionArg> GenAction { get; set; }
|
||||
|
||||
//private static long _StartTimeTick = 0;
|
||||
//private static long _BaseTimeTick = 0;
|
||||
|
||||
|
||||
public SnowWorkerM1(IdGeneratorOptions options)
|
||||
{
|
||||
// 1.BaseTime
|
||||
if (options.BaseTime != DateTime.MinValue)
|
||||
{
|
||||
BaseTime = options.BaseTime;
|
||||
}
|
||||
|
||||
// 2.WorkerIdBitLength
|
||||
if (options.WorkerIdBitLength == 0)
|
||||
{
|
||||
WorkerIdBitLength = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkerIdBitLength = options.WorkerIdBitLength;
|
||||
}
|
||||
|
||||
// 3.WorkerId
|
||||
WorkerId = options.WorkerId;
|
||||
|
||||
// 4.SeqBitLength
|
||||
if (options.SeqBitLength == 0)
|
||||
{
|
||||
SeqBitLength = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
SeqBitLength = options.SeqBitLength;
|
||||
}
|
||||
|
||||
// 5.MaxSeqNumber
|
||||
if (options.MaxSeqNumber <= 0)
|
||||
{
|
||||
MaxSeqNumber = (1 << SeqBitLength) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxSeqNumber = options.MaxSeqNumber;
|
||||
}
|
||||
|
||||
// 6.MinSeqNumber
|
||||
MinSeqNumber = options.MinSeqNumber;
|
||||
|
||||
// 7.Others
|
||||
TopOverCostCount = options.TopOverCostCount;
|
||||
//if (TopOverCostCount == 0)
|
||||
//{
|
||||
// TopOverCostCount = 2000;
|
||||
//}
|
||||
|
||||
_TimestampShift = (byte)(WorkerIdBitLength + SeqBitLength);
|
||||
_CurrentSeqNumber = options.MinSeqNumber;
|
||||
|
||||
//_BaseTimeTick = BaseTime.Ticks;
|
||||
//_StartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private void DoGenIdAction(OverCostActionArg arg)
|
||||
{
|
||||
//return;
|
||||
Task.Run(() =>
|
||||
{
|
||||
GenAction(arg);
|
||||
});
|
||||
}
|
||||
|
||||
private void BeginOverCostAction(in long useTimeTick)
|
||||
{
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
1,
|
||||
_OverCostCountInOneTerm,
|
||||
_GenCountInOneTerm,
|
||||
_TermIndex));
|
||||
}
|
||||
|
||||
private void EndOverCostAction(in long useTimeTick)
|
||||
{
|
||||
//if (_TermIndex > 10000)
|
||||
//{
|
||||
// _TermIndex = 0;
|
||||
//}
|
||||
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
2,
|
||||
_OverCostCountInOneTerm,
|
||||
_GenCountInOneTerm,
|
||||
_TermIndex));
|
||||
}
|
||||
|
||||
private void BeginTurnBackAction(in long useTimeTick)
|
||||
{
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
8,
|
||||
0,
|
||||
0,
|
||||
_TurnBackIndex));
|
||||
}
|
||||
|
||||
private void EndTurnBackAction(in long useTimeTick)
|
||||
{
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
9,
|
||||
0,
|
||||
0,
|
||||
_TurnBackIndex));
|
||||
}
|
||||
#endif
|
||||
|
||||
protected virtual long NextOverCostId()
|
||||
{
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (currentTimeTick > _LastTimeTick)
|
||||
{
|
||||
#if DEBUG
|
||||
EndOverCostAction(currentTimeTick);
|
||||
_GenCountInOneTerm = 0;
|
||||
#endif
|
||||
_LastTimeTick = currentTimeTick;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = false;
|
||||
_OverCostCountInOneTerm = 0;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_OverCostCountInOneTerm >= TopOverCostCount)
|
||||
{
|
||||
#if DEBUG
|
||||
EndOverCostAction(currentTimeTick);
|
||||
_GenCountInOneTerm = 0;
|
||||
#endif
|
||||
// TODO: 在漂移终止,等待时间对齐时,如果发生时间回拨较长,则此处可能等待较长时间。可优化为:在漂移终止时增加时间回拨应对逻辑。(该情况发生概率低,暂不处理)
|
||||
|
||||
_LastTimeTick = GetNextTimeTick();
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = false;
|
||||
_OverCostCountInOneTerm = 0;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_CurrentSeqNumber > MaxSeqNumber)
|
||||
{
|
||||
#if DEBUG
|
||||
_GenCountInOneTerm++;
|
||||
#endif
|
||||
_LastTimeTick++;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = true;
|
||||
_OverCostCountInOneTerm++;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
_GenCountInOneTerm++;
|
||||
#endif
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
protected virtual long NextNormalId()
|
||||
{
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (currentTimeTick < _LastTimeTick)
|
||||
{
|
||||
if (_TurnBackTimeTick < 1)
|
||||
{
|
||||
_TurnBackTimeTick = _LastTimeTick - 1;
|
||||
|
||||
_TurnBackIndex++;
|
||||
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
|
||||
// 支持4次回拨次序(避免回拨重叠导致ID重复),可无限次回拨(次序循环使用)。
|
||||
if (_TurnBackIndex > 4)
|
||||
{
|
||||
_TurnBackIndex = 1;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
BeginTurnBackAction(_TurnBackTimeTick);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Thread.Sleep(1);
|
||||
return CalcTurnBackId(_TurnBackTimeTick);
|
||||
}
|
||||
|
||||
// 时间追平时,_TurnBackTimeTick清零
|
||||
if (_TurnBackTimeTick > 0)
|
||||
{
|
||||
#if DEBUG
|
||||
EndTurnBackAction(_TurnBackTimeTick);
|
||||
#endif
|
||||
_TurnBackTimeTick = 0;
|
||||
}
|
||||
|
||||
if (currentTimeTick > _LastTimeTick)
|
||||
{
|
||||
_LastTimeTick = currentTimeTick;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_CurrentSeqNumber > MaxSeqNumber)
|
||||
{
|
||||
#if DEBUG
|
||||
BeginOverCostAction(currentTimeTick);
|
||||
_TermIndex++;
|
||||
_GenCountInOneTerm = 1;
|
||||
#endif
|
||||
_OverCostCountInOneTerm = 1;
|
||||
_LastTimeTick++;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = true;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
protected virtual long CalcId(long useTimeTick)
|
||||
{
|
||||
var result = ((useTimeTick << _TimestampShift) +
|
||||
((long)WorkerId << SeqBitLength) +
|
||||
(uint)_CurrentSeqNumber);
|
||||
|
||||
_CurrentSeqNumber++;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual long CalcTurnBackId(long useTimeTick)
|
||||
{
|
||||
var result = ((useTimeTick << _TimestampShift) +
|
||||
((long)WorkerId << SeqBitLength) + _TurnBackIndex);
|
||||
|
||||
_TurnBackTimeTick--;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual long GetCurrentTimeTick()
|
||||
{
|
||||
//return (long)(DateTime.UtcNow - BaseTime).Ticks;
|
||||
//return (long)(_StartTimeTick + Environment.TickCount);
|
||||
return (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds;
|
||||
}
|
||||
|
||||
protected virtual long GetNextTimeTick()
|
||||
{
|
||||
long tempTimeTicker = GetCurrentTimeTick();
|
||||
|
||||
while (tempTimeTicker <= _LastTimeTick)
|
||||
{
|
||||
//Thread.Sleep(1);
|
||||
SpinWait.SpinUntil(() => false, 1);
|
||||
tempTimeTicker = GetCurrentTimeTick();
|
||||
}
|
||||
|
||||
return tempTimeTicker;
|
||||
}
|
||||
|
||||
|
||||
public virtual long NextId()
|
||||
{
|
||||
lock (_SyncLock)
|
||||
{
|
||||
return _IsOverCost ? NextOverCostId() : NextNormalId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 常规雪花算法
|
||||
/// </summary>
|
||||
internal class SnowWorkerM2 : SnowWorkerM1
|
||||
{
|
||||
public SnowWorkerM2(IdGeneratorOptions options) : base(options)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override long NextId()
|
||||
{
|
||||
lock (_SyncLock)
|
||||
{
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (_LastTimeTick == currentTimeTick)
|
||||
{
|
||||
if (_CurrentSeqNumber++ > MaxSeqNumber)
|
||||
{
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
currentTimeTick = GetNextTimeTick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
}
|
||||
|
||||
if (currentTimeTick < _LastTimeTick)
|
||||
{
|
||||
throw new Exception(string.Format("Time error for {0} milliseconds", _LastTimeTick - currentTimeTick));
|
||||
}
|
||||
|
||||
_LastTimeTick = currentTimeTick;
|
||||
var result = ((currentTimeTick << _TimestampShift) + ((long)WorkerId << SeqBitLength) + (uint)_CurrentSeqNumber);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花漂移算法(支持数据中心ID和秒级时间戳)
|
||||
/// </summary>
|
||||
internal class SnowWorkerM3 : SnowWorkerM1
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据中心ID(默认0)
|
||||
/// </summary>
|
||||
protected readonly uint DataCenterId = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 数据中心ID长度(默认0)
|
||||
/// </summary>
|
||||
protected readonly byte DataCenterIdBitLength = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 时间戳类型(0-毫秒,1-秒),默认0
|
||||
/// </summary>
|
||||
protected readonly byte TimestampType = 0;
|
||||
|
||||
|
||||
public SnowWorkerM3(IdGeneratorOptions options) : base(options)
|
||||
{
|
||||
// 秒级时间戳类型
|
||||
TimestampType = options.TimestampType;
|
||||
|
||||
// DataCenter相关
|
||||
DataCenterId = options.DataCenterId;
|
||||
DataCenterIdBitLength = options.DataCenterIdBitLength;
|
||||
|
||||
if (TimestampType == 1)
|
||||
{
|
||||
TopOverCostCount = 0;
|
||||
}
|
||||
_TimestampShift = (byte)(DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength);
|
||||
}
|
||||
|
||||
protected override long CalcId(long useTimeTick)
|
||||
{
|
||||
var result = ((useTimeTick << _TimestampShift) +
|
||||
((long)DataCenterId << DataCenterIdBitLength) +
|
||||
((long)WorkerId << SeqBitLength) +
|
||||
(long)_CurrentSeqNumber);
|
||||
|
||||
_CurrentSeqNumber++;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override long CalcTurnBackId(long useTimeTick)
|
||||
{
|
||||
var result = ((useTimeTick << _TimestampShift) +
|
||||
((long)DataCenterId << DataCenterIdBitLength) +
|
||||
((long)WorkerId << SeqBitLength) +
|
||||
_TurnBackIndex);
|
||||
|
||||
_TurnBackTimeTick--;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override long GetCurrentTimeTick()
|
||||
{
|
||||
return TimestampType == 0 ?
|
||||
(long)(DateTime.UtcNow - BaseTime).TotalMilliseconds :
|
||||
(long)(DateTime.UtcNow - BaseTime).TotalSeconds;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认实现
|
||||
/// </summary>
|
||||
public class DefaultIdGenerator : IIdGenerator
|
||||
{
|
||||
private ISnowWorker _SnowWorker { get; set; }
|
||||
|
||||
//public Action<OverCostActionArg> GenIdActionAsync
|
||||
//{
|
||||
// get => _SnowWorker.GenAction;
|
||||
// set => _SnowWorker.GenAction = value;
|
||||
//}
|
||||
|
||||
|
||||
public DefaultIdGenerator(IdGeneratorOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentException("options error.");
|
||||
}
|
||||
|
||||
// 1.BaseTime
|
||||
if (options.BaseTime < DateTime.Now.AddYears(-50) || options.BaseTime > DateTime.Now)
|
||||
{
|
||||
throw new ArgumentException("BaseTime error.");
|
||||
}
|
||||
|
||||
// 2.WorkerIdBitLength
|
||||
int maxLength = options.TimestampType == 0 ? 22 : 31; // (秒级时间戳时放大到31位)
|
||||
if (options.WorkerIdBitLength <= 0)
|
||||
{
|
||||
throw new ArgumentException("WorkerIdBitLength error.(range:[1, 21])");
|
||||
}
|
||||
if (options.DataCenterIdBitLength + options.WorkerIdBitLength + options.SeqBitLength > maxLength)
|
||||
{
|
||||
throw new ArgumentException("error:DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength <= " + maxLength);
|
||||
}
|
||||
|
||||
// 3.WorkerId & DataCenterId
|
||||
var maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
|
||||
if (maxWorkerIdNumber == 0)
|
||||
{
|
||||
maxWorkerIdNumber = 63;
|
||||
}
|
||||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber)
|
||||
{
|
||||
throw new ArgumentException("WorkerId error. (range:[0, " + maxWorkerIdNumber + "]");
|
||||
}
|
||||
|
||||
var maxDataCenterIdNumber = (1 << options.DataCenterIdBitLength) - 1;
|
||||
if (options.DataCenterId < 0 || options.DataCenterId > maxDataCenterIdNumber)
|
||||
{
|
||||
throw new ArgumentException("DataCenterId error. (range:[0, " + maxDataCenterIdNumber + "]");
|
||||
}
|
||||
|
||||
// 4.SeqBitLength
|
||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21)
|
||||
{
|
||||
throw new ArgumentException("SeqBitLength error. (range:[2, 21])");
|
||||
}
|
||||
|
||||
// 5.MaxSeqNumber
|
||||
var maxSeqNumber = (1 << options.SeqBitLength) - 1;
|
||||
if (maxSeqNumber == 0)
|
||||
{
|
||||
maxSeqNumber = 63;
|
||||
}
|
||||
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber)
|
||||
{
|
||||
throw new ArgumentException("MaxSeqNumber error. (range:[1, " + maxSeqNumber + "]");
|
||||
}
|
||||
|
||||
// 6.MinSeqNumber
|
||||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber)
|
||||
{
|
||||
throw new ArgumentException("MinSeqNumber error. (range:[5, " + maxSeqNumber + "]");
|
||||
}
|
||||
|
||||
// 7.TopOverCostCount
|
||||
if (options.TopOverCostCount < 0 || options.TopOverCostCount > 10000)
|
||||
{
|
||||
throw new ArgumentException("TopOverCostCount error. (range:[0, 10000]");
|
||||
}
|
||||
|
||||
switch (options.Method)
|
||||
{
|
||||
case 2:
|
||||
_SnowWorker = new SnowWorkerM2(options);
|
||||
break;
|
||||
default:
|
||||
if (options.DataCenterIdBitLength == 0 && options.TimestampType == 0)
|
||||
{
|
||||
_SnowWorker = new SnowWorkerM1(options);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowWorker = new SnowWorkerM3(options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (options.Method != 2)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public long NewLong()
|
||||
{
|
||||
return _SnowWorker.NextId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 这是一个调用的例子,默认情况下,单机集成者可以直接使用 NextId()。
|
||||
/// </summary>
|
||||
public class YitIdHelper
|
||||
{
|
||||
private static IIdGenerator _IdGenInstance = null;
|
||||
|
||||
public static IIdGenerator IdGenInstance => _IdGenInstance;
|
||||
|
||||
/// <summary>
|
||||
/// 设置参数,建议程序初始化时执行一次
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public static void SetIdGenerator(IdGeneratorOptions options)
|
||||
{
|
||||
_IdGenInstance = new DefaultIdGenerator(options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成新的Id
|
||||
/// 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。
|
||||
/// 否则将会初始化一个WorkerId为1的对象。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long NextId()
|
||||
{
|
||||
if (_IdGenInstance == null)
|
||||
{
|
||||
_IdGenInstance = new DefaultIdGenerator(
|
||||
new IdGeneratorOptions() { WorkerId = 1 }
|
||||
);
|
||||
}
|
||||
|
||||
return _IdGenInstance.NewLong();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Infrastructure.Test
|
||||
{
|
||||
class TestAutoMapper
|
||||
{
|
||||
[Test]
|
||||
public void TestConvert()
|
||||
{
|
||||
var my = new MyClass
|
||||
{
|
||||
Name = "yubao"
|
||||
};
|
||||
|
||||
var dest = my.MapTo<DestClass>();
|
||||
Console.WriteLine(JsonHelper.Instance.Serialize(dest));
|
||||
}
|
||||
[Test]
|
||||
public void TestConvertList()
|
||||
{
|
||||
var users = new List<MyClass> {
|
||||
new MyClass {Name = "yubaolee1"}
|
||||
, new MyClass{Name = "yubaolee2"}
|
||||
|
||||
};
|
||||
|
||||
var dest = users.MapToList<MyClass, DestClass>();
|
||||
Console.WriteLine(JsonHelper.Instance.Serialize(dest));
|
||||
|
||||
var dest2 = users.MapToList<DestClass>();
|
||||
Console.WriteLine(JsonHelper.Instance.Serialize(dest2));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MyClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string NickName { get; set; }
|
||||
}
|
||||
|
||||
class DestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Infrastructure.Test
|
||||
{
|
||||
public class TestDynamicLinq
|
||||
{
|
||||
[Test]
|
||||
public void Convert()
|
||||
{
|
||||
FilterGroup sub = new FilterGroup
|
||||
{
|
||||
Operation = "or"
|
||||
};
|
||||
sub.Filters = new[]
|
||||
{
|
||||
new Filter {Key = "name", Value = "name", Contrast = "=="},
|
||||
new Filter {Key = "c3", Value = "10,20,30", Contrast = "in"}
|
||||
};
|
||||
|
||||
FilterGroup filterGroup = new FilterGroup
|
||||
{
|
||||
Operation = "and"
|
||||
};
|
||||
filterGroup.Filters = new[]
|
||||
{
|
||||
new Filter {Key = "c1", Value = "name", Contrast = "contains"},
|
||||
new Filter {Key = "10,20,30", Value = "40", Contrast = "intersect"}
|
||||
};
|
||||
|
||||
filterGroup.Children = new[]
|
||||
{
|
||||
sub
|
||||
};
|
||||
|
||||
var expression = DynamicLinq.ConvertGroup<TestOjb>(filterGroup,
|
||||
Expression.Parameter(typeof(TestOjb), "c"));
|
||||
|
||||
Console.WriteLine(expression.ToString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class TestOjb{
|
||||
public string c1 { get; set; }
|
||||
public string c2 { get; set; }
|
||||
public string c3 { get; set; }
|
||||
public string c4 { get; set; }
|
||||
public string c5 { get; set; }
|
||||
public string c6 { get; set; }
|
||||
public string c7 { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace Infrastructure.Test
|
||||
{
|
||||
class TestSnowflake
|
||||
{
|
||||
[Test]
|
||||
public void Generate()
|
||||
{
|
||||
// 全局初始化设置WorkerId,默认最大2^16-1。(初始化过程全局只需一次,且必须最先设置)
|
||||
var options = new IdGeneratorOptions()
|
||||
{
|
||||
Method = 1,
|
||||
WorkerId = 1
|
||||
};
|
||||
|
||||
YitIdHelper.SetIdGenerator(options);
|
||||
long newId = YitIdHelper.NextId();
|
||||
Console.WriteLine("=====================================");
|
||||
Console.WriteLine("生成的 Id:" + newId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
public class TreeItem<T>
|
||||
{
|
||||
public T Item { get; set; }
|
||||
public IEnumerable<TreeItem<T>> Children { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
using Infrastructure.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Utilities
|
||||
{
|
||||
public static class DESEncrypt
|
||||
{
|
||||
private static readonly string key = "hopetry###***";
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 加密
|
||||
//
|
||||
// 参数:
|
||||
// Text:
|
||||
// 需要加密的内容
|
||||
public static string Encrypt(string Text)
|
||||
{
|
||||
return Encrypt(Text, key);
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 加密数据
|
||||
//
|
||||
// 参数:
|
||||
// Text:
|
||||
// 需要加密的内容
|
||||
//
|
||||
// sKey:
|
||||
// 秘钥
|
||||
public static string Encrypt(string Text, string sKey)
|
||||
{
|
||||
DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider();
|
||||
byte[] bytes = Encoding.Default.GetBytes(Text);
|
||||
dESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes(Md5Helper.Hash(sKey).ToUpper().Substring(0, 8));
|
||||
dESCryptoServiceProvider.IV = Encoding.ASCII.GetBytes(Md5Helper.Hash(sKey).ToUpper().Substring(0, 8));
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateEncryptor(), CryptoStreamMode.Write);
|
||||
cryptoStream.Write(bytes, 0, bytes.Length);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
byte[] array = memoryStream.ToArray();
|
||||
foreach (byte b in array)
|
||||
{
|
||||
stringBuilder.AppendFormat("{0:X2}", b);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 解密
|
||||
//
|
||||
// 参数:
|
||||
// Text:
|
||||
// 需要解密的内容
|
||||
public static string Decrypt(string Text)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
return Decrypt(Text, key);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// 解密数据
|
||||
//
|
||||
// 参数:
|
||||
// Text:
|
||||
// 需要解密的内容
|
||||
//
|
||||
// sKey:
|
||||
// 秘钥
|
||||
public static string Decrypt(string Text, string sKey)
|
||||
{
|
||||
DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider();
|
||||
int num = Text.Length / 2;
|
||||
byte[] array = new byte[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
int num2 = Convert.ToInt32(Text.Substring(i * 2, 2), 16);
|
||||
array[i] = (byte)num2;
|
||||
}
|
||||
|
||||
dESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes(Md5Helper.Hash(sKey).ToUpper().Substring(0, 8));
|
||||
dESCryptoServiceProvider.IV = Encoding.ASCII.GetBytes(Md5Helper.Hash(sKey).ToUpper().Substring(0, 8));
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateDecryptor(), CryptoStreamMode.Write);
|
||||
cryptoStream.Write(array, 0, array.Length);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
return Encoding.Default.GetString(memoryStream.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
|
||||
namespace Infrastructure.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态属性Bag
|
||||
/// </summary>
|
||||
public class DynamicPropertyBag : DynamicObject
|
||||
{
|
||||
private Dictionary<string, object> storage = new Dictionary<string, object>();
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
if (storage.ContainsKey(binder.Name))
|
||||
{
|
||||
result = storage[binder.Name];
|
||||
return true;
|
||||
}
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
string key = binder.Name;
|
||||
if (storage.ContainsKey(key))
|
||||
storage[key] = value;
|
||||
else
|
||||
storage.Add(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringWriter message = new StringWriter();
|
||||
foreach (var item in storage)
|
||||
message.WriteLine("{0}:\t{1}", item.Key, item.Value);
|
||||
return message.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using Infrastructure.Extensions.AutofacManager;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Infrastructure.Utilities
|
||||
{
|
||||
public static class HttpContextUtil
|
||||
{
|
||||
private static IHttpContextAccessor _accessor=AutofacContainerModule.GetService<IHttpContextAccessor>();
|
||||
|
||||
public static Microsoft.AspNetCore.Http.HttpContext Current => _accessor.HttpContext;
|
||||
|
||||
/// <summary>
|
||||
/// 获取租户ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetTenantId(this IHttpContextAccessor accessor)
|
||||
{
|
||||
string tenantId = "OpenAuthDBContext";
|
||||
|
||||
if (accessor != null && accessor.HttpContext != null)
|
||||
{
|
||||
//读取多租户ID
|
||||
var httpTenantId = accessor.HttpContext.Request.Query[Define.TENANT_ID];
|
||||
if (string.IsNullOrEmpty(httpTenantId))
|
||||
{
|
||||
httpTenantId = accessor.HttpContext.Request.Headers[Define.TENANT_ID];
|
||||
}
|
||||
|
||||
//如果没有租户id,或租户用的是默认的OpenAuthDBContext,则不做任何调整
|
||||
if (!string.IsNullOrEmpty(httpTenantId))
|
||||
{
|
||||
tenantId = httpTenantId;
|
||||
}
|
||||
}
|
||||
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Infrastructure.Utilities
|
||||
{
|
||||
public class HttpManager
|
||||
{
|
||||
public static Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null)
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.Method = "POST";
|
||||
if (!string.IsNullOrEmpty(contentType))
|
||||
{
|
||||
request.ContentType = contentType;
|
||||
}
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
request.Headers[header.Key] = header.Value;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(postData ?? "");
|
||||
using (Stream sendStream = request.GetRequestStream())
|
||||
{
|
||||
sendStream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||
{
|
||||
Stream responseStream = response.GetResponseStream();
|
||||
StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
|
||||
return streamReader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromResult(ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
public static Task<string> HttpGetAsync(string url, Dictionary<string, string> headers = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
request.Headers[header.Key] = header.Value;
|
||||
}
|
||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||
{
|
||||
Stream responseStream = response.GetResponseStream();
|
||||
StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
|
||||
return streamReader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromResult(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue