using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.Json.Serialization; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using WalkingTec.Mvvm.Core; using WalkingTec.Mvvm.Core.Auth; using WalkingTec.Mvvm.Core.Extensions; using WalkingTec.Mvvm.Core.Implement; using WalkingTec.Mvvm.Core.Support.Json; namespace WalkingTec.Mvvm.Mvc { public abstract class BaseApiController : ControllerBase, IBaseController { [JsonIgnore] [BindNever] public WTMContext Wtm { get; set; } [JsonIgnore] [BindNever] public Configs ConfigInfo { get => Wtm?.ConfigInfo; } [JsonIgnore] [BindNever] public GlobalData GlobaInfo { get => Wtm?.GlobaInfo; } [JsonIgnore] [BindNever] public IDistributedCache Cache { get => Wtm?.Cache; } [JsonIgnore] [BindNever] public string CurrentCS { get => Wtm?.CurrentCS; } [JsonIgnore] [BindNever] public DBTypeEnum? CurrentDbType { get => Wtm?.CurrentDbType; } [JsonIgnore] [BindNever] public IDataContext DC { get => Wtm?.DC; } [JsonIgnore] [BindNever] public string BaseUrl { get => Wtm?.BaseUrl; } [JsonIgnore] [BindNever] public IStringLocalizer Localizer { get => Wtm?.Localizer; } //-------------------------------------------方法------------------------------------// //#region CreateVM ///// ///// Create a ViewModel, and pass Session,cache,dc...etc to the viewmodel ///// ///// The type of the viewmodel ///// If the viewmodel is a BaseCRUDVM, the data having this id will be fetched ///// If the viewmodel is a BatchVM, the BatchVM's Ids property will be assigned ///// properties of the viewmodel that you want to assign values ///// if true, the viewmodel will not call InitVM internally ///// ViewModel //[NonAction] //private BaseVM CreateVM(Type VMType, object Id = null, object[] Ids = null, Dictionary values = null, bool passInit = false) //{ // //通过反射创建ViewModel并赋值 // var ctor = VMType.GetConstructor(Type.EmptyTypes); // BaseVM rv = ctor.Invoke(null) as BaseVM; // rv.Wtm = Wtm; // rv.FC = new Dictionary(); // rv.CreatorAssembly = this.GetType().AssemblyQualifiedName; // rv.ControllerName = this.GetType().FullName; // if (HttpContext != null && HttpContext.Request != null) // { // try // { // if (Request.QueryString != QueryString.Empty) // { // foreach (var key in Request.Query.Keys) // { // if (rv.FC.Keys.Contains(key) == false) // { // rv.FC.Add(key, Request.Query[key]); // } // } // } // var f = HttpContext.Request.Form; // foreach (var key in f.Keys) // { // if (rv.FC.Keys.Contains(key) == false) // { // rv.FC.Add(key, f[key]); // } // } // } // catch { } // } // //如果传递了默认值,则给vm赋值 // if (values != null) // { // foreach (var v in values) // { // PropertyHelper.SetPropertyValue(rv, v.Key, v.Value, null, false); // } // } // //如果ViewModel T继承自BaseCRUDVM<>且Id有值,那么自动调用ViewModel的GetById方法 // if (Id != null && rv is IBaseCRUDVM cvm) // { // cvm.SetEntityById(Id); // } // //如果ViewModel T继承自IBaseBatchVM,则自动为其中的ListVM和EditModel初始化数据 // if (rv is IBaseBatchVM temp) // { // temp.Ids = new string[] { }; // if (Ids != null) // { // var tempids = new List(); // foreach (var iid in Ids) // { // tempids.Add(iid.ToString()); // } // temp.Ids = tempids.ToArray(); // } // if (temp.ListVM != null) // { // temp.ListVM.CopyContext(rv); // temp.ListVM.Ids = Ids == null ? new List() : temp.Ids.ToList(); // temp.ListVM.SearcherMode = ListVMSearchModeEnum.Batch; // temp.ListVM.NeedPage = false; // } // if (temp.LinkedVM != null) // { // temp.LinkedVM.CopyContext(rv); // } // if (temp.ListVM != null) // { // //绑定ListVM的OnAfterInitList事件,当ListVM的InitList完成时,自动将操作列移除 // temp.ListVM.OnAfterInitList += (self) => // { // self.RemoveActionColumn(); // self.RemoveAction(); // if (temp.ErrorMessage.Count > 0) // { // self.AddErrorColumn(); // } // }; // if (temp.ListVM.Searcher != null) // { // var searcher = temp.ListVM.Searcher; // searcher.CopyContext(rv); // if (passInit == false) // { // searcher.DoInit(); // } // } // } // temp.LinkedVM?.DoInit(); // //temp.ListVM?.DoSearch(); // } // //如果ViewModel是ListVM,则初始化Searcher并调用Searcher的InitVM方法 // if (rv is IBasePagedListVM lvm) // { // var searcher = lvm.Searcher; // searcher.CopyContext(rv); // if (passInit == false) // { // //获取保存在Cookie中的搜索条件的值,并自动给Searcher中的对应字段赋值 // string namePre = ConfigInfo.CookiePre + "`Searcher" + "`" + rv.VMFullName + "`"; // Type searcherType = searcher.GetType(); // var pros = searcherType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).ToList(); // pros.Add(searcherType.GetProperty("IsValid")); // searcher.DoInit(); // } // } // if (rv is IBaseImport tvm) // { // var template = tvm.Template; // template.CopyContext(rv); // template.DoInit(); // } // //自动调用ViewMode的InitVM方法 // if (passInit == false) // { // rv.DoInit(); // } // return rv; //} ///// ///// Create a ViewModel, and pass Session,cache,dc...etc to the viewmodel ///// ///// The type of the viewmodel ///// If the viewmodel is a BaseCRUDVM, the data having this id will be fetched ///// If the viewmodel is a BatchVM, the BatchVM's Ids property will be assigned ///// use Lambda to set viewmodel's properties,use && for multiply properties, for example Wtm.CreateVM(values: x=>x.Field1=='a' && x.Field2 == 'b'); will set viewmodel's Field1 to 'a' and Field2 to 'b' ///// if true, the viewmodel will not call InitVM internally ///// ViewModel //[NonAction] //public T Wtm.CreateVM(object Id = null, object[] Ids = null, Expression> values = null, bool passInit = false) where T : BaseVM //{ // SetValuesParser p = new SetValuesParser(); // var dir = p.Parse(values); // return CreateVM(typeof(T), Id, Ids, dir, passInit) as T; //} ///// ///// Create a ViewModel, and pass Session,cache,dc...etc to the viewmodel ///// ///// the fullname of the viewmodel's type ///// If the viewmodel is a BaseCRUDVM, the data having this id will be fetched ///// If the viewmodel is a BatchVM, the BatchVM's Ids property will be assigned ///// if true, the viewmodel will not call InitVM internally ///// ViewModel //[NonAction] //public BaseVM CreateVM(string VmFullName, object Id = null, object[] Ids = null, bool passInit = false) //{ // return CreateVM(Type.GetType(VmFullName), Id, Ids, null, passInit); //} //#endregion #region ReInit model [NonAction] private void SetReInit(ModelStateDictionary msd, BaseVM model) { var reinit = model.GetType().GetTypeInfo().GetCustomAttributes(typeof(ReInitAttribute), false).Cast().SingleOrDefault(); if (ModelState.IsValid) { if (reinit != null && (reinit.ReInitMode == ReInitModes.SUCCESSONLY || reinit.ReInitMode == ReInitModes.ALWAYS)) { model.DoReInit(); } } else { if (reinit == null || (reinit.ReInitMode == ReInitModes.FAILEDONLY || reinit.ReInitMode == ReInitModes.ALWAYS)) { model.DoReInit(); } } } #endregion #region Validate model [NonAction] public Dictionary RedoValidation(object item) { Dictionary rv = new Dictionary(); TryValidateModel(item); foreach (var e in ControllerContext.ModelState) { if (e.Value.ValidationState == ModelValidationState.Invalid) { rv.Add(e.Key, e.Value.Errors.Select(x => x.ErrorMessage).ToSepratedString()); } } return rv; } #endregion #region update viewmodel /// /// Set viewmodel's properties to the matching items posted by user /// /// ViewModel /// prefix /// true if success [NonAction] public bool RedoUpdateModel(object vm, string prefix = null) { try { BaseVM bvm = vm as BaseVM; foreach (var item in bvm.FC.Keys) { PropertyHelper.SetPropertyValue(vm, item, bvm.FC[item], prefix, true); } return true; } catch { return false; } } #endregion protected JsonResult JsonMore(object data, int statusCode = StatusCodes.Status200OK, string msg = "success") { return new JsonResult(new JsonResultT { Msg = msg, Code = statusCode, Data = data }); } } }