fix #I3O97D 站点启动时自动运行状态为【正在运行】的定时任务;

fix #I3ODHI 增加存储过程调用;
This commit is contained in:
yubaolee 2021-04-28 10:20:24 +08:00
parent 785d784759
commit 4148427f1a
10 changed files with 892 additions and 81 deletions

View File

@ -0,0 +1,17 @@
namespace Infrastructure.Const
{
/// <summary>
/// 定时任务状态
/// </summary>
public enum JobStatus
{
/// <summary>
/// 未启动
/// </summary>
NotRun,
/// <summary>
/// 正在运行
/// </summary>
Running
}
}

View File

@ -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 });
}
}
}

View File

@ -1,14 +1,18 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using System.Xml.Linq;
@ -138,39 +142,41 @@ namespace Infrastructure.Extensions
return objectList;
}
public static object ChangeType(this object convertibleValue, Type type)
{
if (null == convertibleValue) return null;
try
{
if (type == typeof(Guid) || type == typeof(Guid?))
{
string value = convertibleValue.ToString();
if (value == "") return null;
return Guid.Parse(value);
}
if (!type.IsGenericType) return Convert.ChangeType(convertibleValue, type);
if (type.ToString() == "System.Nullable`1[System.Boolean]" || type.ToString() == "System.Boolean")
{
if (convertibleValue.ToString() == "0")
return false;
return true;
}
Type genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Nullable<>))
{
return Convert.ChangeType(convertibleValue, Nullable.GetUnderlyingType(type));
}
}
catch
{
return null;
}
return null;
}
//
// public static object ChangeType(this object convertibleValue, Type type)
// {
// if (null == convertibleValue) return null;
//
// try
// {
// if (type == typeof(Guid) || type == typeof(Guid?))
// {
// string value = convertibleValue.ToString();
// if (value == "") return null;
// return Guid.Parse(value);
// }
//
// if (!type.IsGenericType) return Convert.ChangeType(convertibleValue, type);
// if (type.ToString() == "System.Nullable`1[System.Boolean]" || type.ToString() == "System.Boolean")
// {
// if (convertibleValue.ToString() == "0")
// return false;
// return true;
// }
// Type genericTypeDefinition = type.GetGenericTypeDefinition();
// if (genericTypeDefinition == typeof(Nullable<>))
// {
// return Convert.ChangeType(convertibleValue, Nullable.GetUnderlyingType(type));
// }
// }
// catch
// {
// return null;
// }
// return null;
// }
/// <summary>
/// 将集合转换为数据集。
/// </summary>
@ -1193,6 +1199,269 @@ namespace Infrastructure.Extensions
{
return EmailRegex.IsMatch(email);
}
/// <summary>
/// 将 DateTimeOffset 转换成 DateTime
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime ConvertToDateTime(this DateTimeOffset dateTime)
{
if (dateTime.Offset.Equals(TimeSpan.Zero))
return dateTime.UtcDateTime;
else if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
return DateTime.SpecifyKind(dateTime.DateTime, DateTimeKind.Local);
else
return dateTime.DateTime;
}
/// <summary>
/// 将 DateTime 转换成 DateTimeOffset
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
{
return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
/// <summary>
/// 判断是否是富基元类型
/// </summary>
/// <param name="type">类型</param>
/// <returns></returns>
internal static bool IsRichPrimitive(this Type type)
{
// 处理元组类型
if (type.IsValueTuple()) return false;
// 处理数组类型,基元数组类型也可以是基元类型
if (type.IsArray) return type.GetElementType().IsRichPrimitive();
// 基元类型或值类型或字符串类型
if (type.IsPrimitive || type.IsValueType || type == typeof(string)) return true;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) return type.GenericTypeArguments[0].IsRichPrimitive();
return false;
}
/// <summary>
/// 合并两个字典
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dic">字典</param>
/// <param name="newDic">新字典</param>
/// <returns></returns>
internal static Dictionary<string, T> AddOrUpdate<T>(this Dictionary<string, T> dic, Dictionary<string, T> newDic)
{
foreach (var key in newDic.Keys)
{
if (dic.ContainsKey(key))
dic[key] = newDic[key];
else
dic.Add(key, newDic[key]);
}
return dic;
}
/// <summary>
/// 判断是否是元组类型
/// </summary>
/// <param name="type">类型</param>
/// <returns></returns>
internal static bool IsValueTuple(this Type type)
{
return type.ToString().StartsWith(typeof(ValueTuple).FullName);
}
/// <summary>
/// 判断方法是否是异步
/// </summary>
/// <param name="method">方法</param>
/// <returns></returns>
internal static bool IsAsync(this MethodInfo method)
{
return method.ReturnType.IsAsync();
}
/// <summary>
/// 判断类型是否是异步类型
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal static bool IsAsync(this Type type)
{
return type.ToString().StartsWith(typeof(Task).FullName);
}
/// <summary>
/// 判断类型是否实现某个泛型
/// </summary>
/// <param name="type">类型</param>
/// <param name="generic">泛型类型</param>
/// <returns>bool</returns>
internal static bool HasImplementedRawGeneric(this Type type, Type generic)
{
// 检查接口类型
var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
if (isTheRawGenericType) return true;
// 检查类型
while (type != null && type != typeof(object))
{
isTheRawGenericType = IsTheRawGenericType(type);
if (isTheRawGenericType) return true;
type = type.BaseType;
}
return false;
// 判断逻辑
bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
}
/// <summary>
/// 判断是否是匿名类型
/// </summary>
/// <param name="obj">对象</param>
/// <returns></returns>
internal static bool IsAnonymous(this object obj)
{
var type = obj.GetType();
return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
&& type.IsGenericType && type.Name.Contains("AnonymousType")
&& (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
&& type.Attributes.HasFlag(TypeAttributes.NotPublic);
}
/// <summary>
/// 获取所有祖先类型
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal static IEnumerable<Type> GetAncestorTypes(this Type type)
{
var ancestorTypes = new List<Type>();
while (type != null && type != typeof(object))
{
if (IsNoObjectBaseType(type))
{
var baseType = type.BaseType;
ancestorTypes.Add(baseType);
type = baseType;
}
else break;
}
return ancestorTypes;
static bool IsNoObjectBaseType(Type type) => type.BaseType != typeof(object);
}
/// <summary>
/// 获取方法真实返回类型
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
internal static Type GetRealReturnType(this MethodInfo method)
{
// 判断是否是异步方法
var isAsyncMethod = method.IsAsync();
// 获取类型返回值并处理 Task 和 Task<T> 类型返回值
var returnType = method.ReturnType;
return isAsyncMethod ? (returnType.GenericTypeArguments.FirstOrDefault() ?? typeof(void)) : returnType;
}
/// <summary>
/// 首字母大写
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
internal static string ToTitleCase(this string str)
{
return Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(str);
}
/// <summary>
/// 将一个对象转换为指定类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
internal static T ChangeType<T>(this object obj)
{
return (T)ChangeType(obj, typeof(T));
}
/// <summary>
/// 将一个对象转换为指定类型
/// </summary>
/// <param name="obj">待转换的对象</param>
/// <param name="type">目标类型</param>
/// <returns>转换后的对象</returns>
internal static object ChangeType(this object obj, Type type)
{
if (type == null) return obj;
if (obj == null) return type.IsValueType ? Activator.CreateInstance(type) : null;
var underlyingType = Nullable.GetUnderlyingType(type);
if (type.IsAssignableFrom(obj.GetType())) return obj;
else if ((underlyingType ?? type).IsEnum)
{
if (underlyingType != null && string.IsNullOrWhiteSpace(obj.ToString())) return null;
else return Enum.Parse(underlyingType ?? type, obj.ToString());
}
// 处理DateTime -> DateTimeOffset 类型
else if (obj.GetType().Equals(typeof(DateTime)) && (underlyingType ?? type).Equals(typeof(DateTimeOffset)))
{
return ((DateTime)obj).ConvertToDateTimeOffset();
}
// 处理 DateTimeOffset -> DateTime 类型
else if (obj.GetType().Equals(typeof(DateTimeOffset)) && (underlyingType ?? type).Equals(typeof(DateTime)))
{
return ((DateTimeOffset)obj).ConvertToDateTime();
}
else if (typeof(IConvertible).IsAssignableFrom(underlyingType ?? type))
{
try
{
return Convert.ChangeType(obj, underlyingType ?? type, null);
}
catch
{
return underlyingType == null ? Activator.CreateInstance(type) : null;
}
}
else
{
var converter = TypeDescriptor.GetConverter(type);
if (converter.CanConvertFrom(obj.GetType())) return converter.ConvertFrom(obj);
var constructor = type.GetConstructor(Type.EmptyTypes);
if (constructor != null)
{
var o = constructor.Invoke(null);
var propertys = type.GetProperties();
var oldType = obj.GetType();
foreach (var property in propertys)
{
var p = oldType.GetProperty(property.Name);
if (property.CanWrite && p != null && p.CanRead)
{
property.SetValue(o, ChangeType(p.GetValue(obj, null), property.PropertyType), null);
}
}
return o;
}
}
return obj;
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Linq;
using Infrastructure;
using OpenAuth.Repository.Domain;
using Quartz;
namespace OpenAuth.App.Extensions
{
/// <summary>
/// 定时任务扩展
/// </summary>
public static class OpenJobExt
{
/// <summary>
/// 启动定时任务
/// </summary>
/// <param name="job"></param>
/// <param name="scheduler">一个Quartz Scheduler</param>
public static void Start(this OpenJob job, IScheduler scheduler)
{
var jobBuilderType = typeof(JobBuilder);
var method = jobBuilderType.GetMethods().FirstOrDefault(
x => x.Name.Equals("Create", StringComparison.OrdinalIgnoreCase) &&
x.IsGenericMethod && x.GetParameters().Length == 0)
?.MakeGenericMethod(Type.GetType(job.JobCall));
var jobBuilder = (JobBuilder) method.Invoke(null, null);
IJobDetail jobDetail = jobBuilder.WithIdentity(job.Id).Build();
jobDetail.JobDataMap[Define.JOBMAPKEY] = job.Id; //传递job信息
ITrigger trigger = TriggerBuilder.Create()
.WithCronSchedule(job.Cron)
.WithIdentity(job.Id)
.StartNow()
.Build();
scheduler.ScheduleJob(jobDetail, trigger);
}
/// <summary>
/// 停止一个定时任务
/// </summary>
/// <param name="job"></param>
/// <param name="scheduler"></param>
public static void Stop(this OpenJob job, IScheduler scheduler)
{
TriggerKey triggerKey = new TriggerKey(job.Id);
// 停止触发器
scheduler.PauseTrigger(triggerKey);
// 移除触发器
scheduler.UnscheduleJob(triggerKey);
// 删除任务
scheduler.DeleteJob(new JobKey(job.Id));
}
}
}

View File

@ -11,17 +11,19 @@ namespace OpenAuth.App.HostedService
{
private readonly ILogger<QuartzService> _logger;
private IScheduler _scheduler;
private OpenJobApp _openJobApp;
public QuartzService(ILogger<QuartzService> logger, IScheduler scheduler)
public QuartzService(ILogger<QuartzService> logger, IScheduler scheduler, OpenJobApp openJobApp)
{
_logger = logger;
_scheduler = scheduler;
_openJobApp = openJobApp;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("启动定时job可以在这里配置读取数据库需要启动的任务然后启动他们");
_scheduler.Start();
_openJobApp.StartAll();
return Task.CompletedTask;
}

View File

@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Infrastructure;
using Infrastructure.Const;
using Microsoft.Extensions.Logging;
using OpenAuth.App.Extensions;
using OpenAuth.App.Interface;
using OpenAuth.App.Jobs;
using OpenAuth.App.Request;
@ -16,6 +18,9 @@ using Quartz;
namespace OpenAuth.App
{
/// <summary>
/// 系统定时任务管理
/// </summary>
public class OpenJobApp : BaseStringApp<OpenJob, OpenAuthDBContext>
{
private SysLogApp _sysLogApp;
@ -41,10 +46,25 @@ namespace OpenAuth.App
return result;
}
/// <summary>
/// 启动所有状态为正在运行的任务
/// <para>通常应用在系统加载的时候</para>
/// </summary>
/// <returns></returns>
public async Task StartAll()
{
var jobs = Repository.Find(u => u.Status == (int) JobStatus.Running);
foreach (var job in jobs)
{
job.Start(_scheduler);
}
_logger.LogInformation("所有状态为正在运行的任务已启动");
}
public void Add(AddOrUpdateOpenJobReq req)
{
var obj = req.MapTo<OpenJob>();
//todo:补充或调整自己需要的字段
obj.CreateTime = DateTime.Now;
var user = _auth.GetCurrentUser().User;
obj.CreateUserId = user.Id;
@ -67,12 +87,11 @@ namespace OpenAuth.App
UpdateTime = DateTime.Now,
UpdateUserId = user.Id,
UpdateUserName = user.Name
//todo:补充或调整自己需要的字段
});
}
#region
/// <summary>
/// 返回系统的job接口
/// </summary>
@ -85,7 +104,7 @@ namespace OpenAuth.App
.ToArray();
return types.Select(u => u.FullName).ToList();
}
public void ChangeJobStatus(ChangeJobStatusReq req)
{
var job = Repository.FirstOrDefault(u => u.Id == req.Id);
@ -93,40 +112,18 @@ namespace OpenAuth.App
{
throw new Exception("任务不存在");
}
if (req.Status == 0) //停止
{
TriggerKey triggerKey = new TriggerKey(job.Id);
// 停止触发器
_scheduler.PauseTrigger(triggerKey);
// 移除触发器
_scheduler.UnscheduleJob(triggerKey);
// 删除任务
_scheduler.DeleteJob(new JobKey(job.Id));
}
else //启动
{
var jobBuilderType = typeof(JobBuilder);
var method = jobBuilderType.GetMethods().FirstOrDefault(
x => x.Name.Equals("Create", StringComparison.OrdinalIgnoreCase) &&
x.IsGenericMethod && x.GetParameters().Length == 0)
?.MakeGenericMethod(Type.GetType(job.JobCall));
var jobBuilder = (JobBuilder)method.Invoke(null, null);
IJobDetail jobDetail = jobBuilder.WithIdentity(job.Id).Build();
jobDetail.JobDataMap[Define.JOBMAPKEY] = job.Id; //传递job信息
ITrigger trigger = TriggerBuilder.Create()
.WithCronSchedule(job.Cron)
.WithIdentity(job.Id)
.StartNow()
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
if (req.Status == (int) JobStatus.NotRun) //停止
{
job.Stop(_scheduler);
}
else //启动
{
job.Start(_scheduler);
}
var user = _auth.GetCurrentUser().User;
job.Status = req.Status;
@ -135,14 +132,13 @@ namespace OpenAuth.App
job.UpdateUserName = user.Name;
Repository.Update(job);
}
/// <summary>
/// 记录任务运行结果
/// </summary>
/// <param name="jobId"></param>
public void RecordRun(string jobId)
{
var job = Repository.FirstOrDefault(u =>u.Id == jobId);
var job = Repository.FirstOrDefault(u => u.Id == jobId);
if (job == null)
{
_sysLogApp.Add(new SysLog
@ -157,7 +153,7 @@ namespace OpenAuth.App
job.RunCount++;
job.LastRunTime = DateTime.Now;
Repository.Update(job);
_sysLogApp.Add(new SysLog
{
CreateName = "Quartz",
@ -172,13 +168,13 @@ namespace OpenAuth.App
#endregion
public OpenJobApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<OpenJob,OpenAuthDBContext> repository,
IAuth auth, SysLogApp sysLogApp, IScheduler scheduler, ILogger<OpenJobApp> logger) : base(unitWork, repository, auth)
public OpenJobApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<OpenJob, OpenAuthDBContext> repository,
IAuth auth, SysLogApp sysLogApp, IScheduler scheduler, ILogger<OpenJobApp> logger) : base(unitWork,
repository, auth)
{
_sysLogApp = sysLogApp;
_scheduler = scheduler;
_logger = logger;
}
}
}

View File

@ -10,6 +10,8 @@
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
@ -107,6 +109,13 @@ namespace OpenAuth.Repository.Interface
/// <returns></returns>
IQueryable<T> Query<T>(string sql, params object[] parameters) where T : class;
/// <summary>
/// 执行存储过程
/// </summary>
/// <param name="procName">存储过程名称</param>
/// <param name="sqlParams">存储过程参数</param>
List<T> ExecProcedure<T>(string procName,params DbParameter[] sqlParams) where T : class;
#region
Task<int> ExecuteSqlRawAsync(string sql);

View File

@ -21,16 +21,14 @@ namespace OpenAuth.Repository
private ILoggerFactory _LoggerFactory;
private IHttpContextAccessor _httpContextAccessor;
private IConfiguration _configuration;
private IOptions<AppSetting> _appConfiguration;
public OpenAuthDBContext(DbContextOptions<OpenAuthDBContext> options, ILoggerFactory loggerFactory,
IHttpContextAccessor httpContextAccessor, IConfiguration configuration, IOptions<AppSetting> appConfiguration)
IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
: base(options)
{
_LoggerFactory = loggerFactory;
_httpContextAccessor = httpContextAccessor;
_configuration = configuration;
_appConfiguration = appConfiguration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

@ -0,0 +1,28 @@
using System;
using System.Linq;
using Infrastructure;
using NUnit.Framework;
using Microsoft.Extensions.DependencyInjection;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
namespace OpenAuth.Repository.Test
{
/// <summary>
/// 测试UnitWork
/// </summary>
class TestUnitWork : TestBase
{
/// <summary>
/// 测试存储过程
/// </summary>
[Test]
public void ExecProcedure()
{
var unitWork = _autofacServiceProvider.GetService<IUnitWork<OpenAuthDBContext>>();
var users = unitWork.ExecProcedure<User>("sp_alluser");
Console.WriteLine(JsonHelper.Instance.Serialize(users));
}
}
}

View File

@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Infrastructure;
using Infrastructure.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using OpenAuth.Repository.Core;
@ -212,8 +216,29 @@ namespace OpenAuth.Repository
{
return _context.Query<T>().FromSqlRaw(sql, parameters);
}
#region
/// <summary>
/// 执行存储过程
/// </summary>
/// <param name="procName">存储过程名称</param>
/// <param name="sqlParams">存储过程参数</param>
public List<T> ExecProcedure<T>(string procName, params DbParameter[] sqlParams) where T : class
{
var connection = _context.Database.GetDbConnection();
using (var cmd = connection.CreateCommand())
{
_context.Database.OpenConnection();
cmd.CommandText = procName;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddRange(sqlParams);
DbDataReader dr = cmd.ExecuteReader();
var datatable = new DataTable();
datatable.Load(dr);
return datatable.ToList<T>();
}
}
#region
/// <summary>
/// 异步执行sql