初始化
WebApplication.CreateBuilder
var builder = WebApplication.CreateBuilder(args);
用于创建一个 Web 应用程序的构建器 (WebApplicationBuilder) 实例。通过这个构建器,你可以配置应用程序的服务和中间件,进而构建和运行你的 ASP.NET Core Web 应用。
builder.WebHost.UseUrls
builder.WebHost.UseUrls("http://*:8080");
用于设置Web服务器所监听的URL和端口。通过这个方法,开发者可以指定应用程序在哪些地址和端口上运行,从而控制外部请求如何到达你的应用程序。
builder.Configuration
builder.Configuration.AddCommandLine(args);
允许你访问应用程序的配置设置,这些设置通常包含在 appsettings.json、环境变量、用户机密、命令行参数等中。builder.Configuration 是 WebApplicationBuilder 的一部分,提供了一种灵活的方式来管理和访问配置。
services.Configure
appsetting.json包含一个secret类型
{
"Secret": {
"ApiKey": "your-api-key-here",
"ConnectionString": "your-connection-string-here"
}
}
public class Secret
{
public string ApiKey { get; set; }
public string ConnectionString { get; set; }
}
builder.Services.Configure<Secret>(builder.Configuration.GetSection("Secret"));
是一个用于将应用程序配置绑定到强类型配置对象的服务注册方法。通过这种方式,你可以轻松地管理和访问应用程序的配置数据,并能够在整个应用程序中以一致的方式使用这些配置。通常用于将从配置源(如 JSON 文件、环境变量等)获取的设置绑定到特定的类型上。
实际应用:
services.Configure<MyConnectionConFig>(configuration.GetSection("SysConnection"));
_connection = provider.GetRequiredService<IOptions<MyConnectionConFig>>().Value;
services.BuildServiceProvider
例子
using Microsoft.Extensions.DependencyInjection;
public interface IMyService
{
string GetMessage();
}
public class MyService : IMyService
{
public string GetMessage() => "Hello, World!";
}
// 创建一个 Service Collection 并注册服务
var services = new ServiceCollection();
services.AddSingleton<IMyService, MyService>(); // 注册服务
// 构建服务提供者
var serviceProvider = services.BuildServiceProvider();
// 解析服务
var myService = serviceProvider.GetService<IMyService>();
// 使用服务
Console.WriteLine(myService.GetMessage());
方法用于构建服务提供者(Service Provider),这是完成依赖注入(DI)配置后的一个重要步骤。通过此方法,我们可以生成一个服务提供者实例,该实例可以用于解析已注册的服务。
builder.Host.UseServiceProviderFactory
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Services.AddDistributedMemoryCache
用于注册一个基于内存的分布式缓存服务。此缓存服务适用于在应用程序的不同实例之间共享缓存的数据,但它仅存储在内存中,因此在应用程序重启或部署后,缓存中的数据会丢失。
builder.Services.AddControllersWithViews().AddRazorRuntimeCompilation()
是在 ASP.NET Core 应用程序中注册支持 MVC 控制器和视图的服务,并启用 Razor 视图运行时编译的代码。这对于开发过程中的视图修改非常有用,可以在不重启应用程序的情况下立即查看更改。
builder.Services.AddSession
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(AppSetting.SessionTimeout);
});
用于注册会话服务,允许你在应用程序中存储用户的会话状态。会话是用于保存用户数据的功能,它在用户与应用程序的多个请求之间保留数据,便于在用户访问不同页面时维持状态。
▷可以方便地在开发阶段快速进行视图修改而无需重启应用程序。
是在 ASP.NET Core 应用程序中注册 API 控制器并添加对 Newtonsoft.Json 序列化支持的代码。这样做通常是为了方便进行复杂的对象序列化和反序列化,尤其是在处理 JSON 数据时。
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>()
是在 ASP.NET Core 应用程序中用于注册 IHttpContextAccessor 服务的代码。这一行的目的是让你可以在应用程序的各个部分访问当前的 HTTP 上下文。
这是 ASP.NET Core 的接口,允许你从非控制器类中访问当前的 HttpContext。对于需要访问 HTTP 请求信息(如请求头、用户信息等)的服务或类,这个接口非常有用。
IHttpContextAccessor 的实例作为单例服务注册到依赖注入容器中。这意味着在整个应用程序的生命周期中,只有一个实例会被创建和使用。这种注册方式非常适合像 IHttpContextAccessor 这样的服务,因为它不持有状态。
builder.Services.TryAddSingleton();
调试
数据表不更新
可能因为里面某些语法错误,导致整个页面异常
layui
固定字段的表格
表格写法如下
html <input type="checkbox" lay-skin="primary">
:在前面设置单选框html <tbody id="content"></tbody>
:这个是数据本体html <div id="paged"></div>
:使用layui的paging模块来更新
<table id="gridList" class="layui-form layui-table table-hover FNMES-table" lay-skin="line">
<thead>
<tr>
<th>
<input type="checkbox" lay-skin="primary">
</th>
<th>工单号</th>
<th>产品</th>
<th>产品备注</th>
<th>数量</th>
<th>计划开始时间</th>
<th>计划完成时间</th>
<th>状态</th>
</tr>
</thead>
<!--内容容器-->
<tbody id="content"></tbody>
</table>
<div id="paged"></div>
使用layui遍历返回的数据
- layui.each:使用的是layui的迭代器
<script id="contentTpl" type="text/html">
{{# layui.each(d.list, function(index, item){ }}
<tr>
<td>
<input type="checkbox" lay-skin="primary" value="{{item.Id}}"></td>
<td>{{item.TaskOrderNumber}}</td>
<td>{{item.ProductPartNo}}</td>
<td>{{item.ProductDescription}}</td>
<td>{{item.PlanQty}}</td>
<td>{{item.PlanStartTime}}</td>
<td>{{item.PlanEndTime}}</td>
<td>{{item.FlagString}}</td>
</tr>
{{# }); }}
{{# if(d.list.length<=0) { }}
<tr style="color: red">
<td colspan="8">查无数据。</td>
</tr>
{{# } }}
</script>
使用layui来更新
- initGrid:将返回的数据更新到表格
- tempElem的值是#contentTpl,指定了更新表格的地方
- elem的值是#content
- paging是layui的分页组件,用于分页浏览表格数据
<script type="text/javascript">
var paging;
layui.config({
base: parent._baseUrl
}).use(['paging', 'form', 'layer'], function () {
var layer = parent.layer || layui.layer;
var form = layui.form;
paging = layui.paging();
$("#lineId").bindSelect({
type: "POST",
url: "/system/line/getListTreeSelect",
title: '请选择线体'
});
initGrid();
});
function initGrid() {
if ($("#lineId").val() == "0") {
return
};
paging.init({
url: '/param/order/index',
elem: '#content',
tempElem: '#contentTpl',
singleSelected: true, //单选
params: {
keyWord: $("#keyWord").val(),
configId: $("#lineId").val(),
index: $('#queryDate').find('button.active').val()
},
pageConfig: {
elem: 'paged',
pageSize: 10,
},
success: function () {
}
});
}
弹窗显示表格
- 按钮用onclick绑定事件btn_data()
- btn_data用layerOpen中content中传递对应的参数
<button class="layui-btn layui-btn-primary layui-btn-small" onclick="btn_data()">查看产品</button>
function btn_data() {
var ids = $("#gridList").gridSelectedRowValue();
if (ids.length != 1) {
$.layerMsg("请勾选单条记录查看。", "warning");
return;
}
$.layerOpen({
id: "data",
title: "查看产品",
width: "1200px",
height: "550px",
content: "/param/order/data?primaryKey=" + ids[0] + "&configId=" + $("#lineId").val(),
btn: null
});
}
var paging;
layui.config({ base: parent._baseUrl }).use(['paging', 'form'], function () {
var form = layui.form;
paging = layui.paging();
var primaryKey = $.getQueryString("primaryKey");
var configId = $.getQueryString("configId");
initGrid(primaryKey,configId);
});
function initGrid(primaryKey, configId) {
paging.init({
url: '/param/order/getData',
elem: '#content',
tempElem: '#contentTpl',
checkbox: true, //是否显示复选框
singleSelected: true, //单选
params: {
primaryKey: primaryKey,
configId: configId,
},
pageConfig: {
elem: 'paged',
pageSize: 10,
},
success: function () {
},
fail: function (msg) {
top.layer.msg(msg);
}
});
}
返回页面,用ViewData传递参数
[Route("param/order/data")]
[HttpGet]
public ActionResult Data(string primaryKey, string configId)
{
ViewData["primaryKey"] = primaryKey;
ViewData["configId"] = configId;
return View();
}
在js文件中用$.getQueryString读取
layui.config({ base: parent._baseUrl }).use(['paging', 'form'], function () {
var form = layui.form;
paging = layui.paging();
var primaryKey = $.getQueryString("primaryKey");
var configId = $.getQueryString("configId");
initGrid(primaryKey,configId);
});
表格弹窗查看
主js写法:
- content: “/param/order/detail?primaryKey=” + ids[0] + “&configId=” + $(“#lineId”).val():传递参数primarykey和configId
- layerOpen:默认使用Get请求方法,C#对应的方法也要使用HttpGet
function btn_detail() {
var ids = $("#gridList").gridSelectedRowValue();
if (ids.length != 1) {
$.layerMsg("请勾选单条记录查看。", "warning");
return;
}
$.layerOpen({
id: "detail",
title: "查看工单",
width: "730px",
height: "400px",
content: "/param/order/detail?primaryKey=" + ids[0] + "&configId=" + $("#lineId").val(),
btn: null
});
}
子html(表单)写法:
- form:表单元素,class=“layui-form”
- class=“layui-form-item”:表单项
<form id="form" class="layui-form" style="margin-top: 25px">
<form id="form" class="layui-form" style="margin-top: 25px">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label label-required">工单号</label>
<div class="layui-input-inline">
<input type="hidden" name="Id" id="Id" />
<input type="hidden" name="ConfigId" id="ConfigId" />
<input type="text" name="TaskOrderNumber" autocomplete="off" class="layui-input" disabled />
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">产品</label>
<div class="layui-input-block">
<input type="text" name="ProductPartNo" autocomplete="off" class="layui-input" disabled />
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">产品描述</label>
<div class="layui-input-block">
<input type="text" name="ProductDescription" autocomplete="off" class="layui-input" disabled />
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">计划数量</label>
<div class="layui-input-block">
<input type="text" name="PlanQty" autocomplete="off" class="layui-input" disabled />
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="text" name="FlagString" autocomplete="off" class="layui-input" disabled />
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">计划开始时间</label>
<div class="layui-input-inline">
<input type="text" name="PlanStartTime" autocomplete="off" class="layui-input" disabled />
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">计划完成时间</label>
<div class="layui-input-inline">
<input type="text" name="PlanEndTime" autocomplete="off" class="layui-input" disabled />
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">上线数量</label>
<div class="layui-input-inline">
<input type="text" name="StartQty" autocomplete="off" class="layui-input" disabled />
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">下线数量</label>
<div class="layui-input-inline">
<input type="text" name="PackQty" autocomplete="off" class="layui-input" disabled />
</div>
</div>
</div>
</form>
C#代码
- 无参数,由url传递参数
[Route("param/order/detail")]
[HttpGet, AuthorizeChecked]
public ActionResult Detail()
{
return View();
}
表单查看(不提交)
主js写法:
- $.layerOpen:弹窗,并传递参数primarykey和configId
function btn_detail() {
var ids = $("#gridList").gridSelectedRowValue();
if (ids.length != 1) {
$.layerMsg("请勾选单条记录查看。", "warning");
return;
}
$.layerOpen({
id: "detail",
title: "查看工单",
width: "730px",
height: "400px",
content: "/param/order/detail?primaryKey=" + ids[0] + "&configId=" + $("#lineId").val(),
btn: null
});
}
C#代码:
- 尽管Detail的参数为空,但是url中会存在primaryKey和configId
[Route("param/order/detail")]
[HttpGet, AuthorizeChecked]
public ActionResult Detail()
{
return View();
}
子js(表单)写法:
- $(“#form”).formSerialize(data):表单反序列
- form.render():表单渲染
layui.use(['element', 'form', 'laydate'], function () {
var form = layui.form;
var element = layui.element;
var laydate = layui.laydate;
laydate.render({
});
//获取url参数
var primaryKey = $.getQueryString("primaryKey");
var configId = $.getQueryString("configId");
if (primaryKey) {
$.ajax({
url: "/param/order/getForm",
data: {
primaryKey: primaryKey,
configId: configId
},
type: "post",
dataType: "json",
async: false,
success: function (data) {
$("#form").formSerialize(data);
}
});
}
form.render();
});
表单渲染对应C#代码:
- 返回的是Content,entity.Tojson()返回的是json字符串
- 会自动对json字符串解释并根据对应的name对元素进行赋值
[Route("param/order/getForm")]
[HttpPost, LoginChecked]
public ActionResult GetForm(string primaryKey, string configId)
{
ParamOrder entity = orderLogic.GetWithQty(long.Parse(primaryKey), configId);
return Content(entity.ToJson());
}
表单提交
主js写法:
- iBody.find(‘#btnSubmit’).click():表单需要提交的话,需要包含这一行
- $.layerOpen:打开默认调用post方法
function btn_edit() {
var ids = $("#gridList").gridSelectedRowValue();
if (ids.length != 1) {
$.layerMsg("请勾选单条记录修改。", "warning");
return;
}
$.layerOpen({
id: "edit",
title: "修改工序",
width: "750px",
height: "400px",
content: "/param/route/form?primaryKey=" + ids[0] + "&configId=" + $("#lineId").val(),
yes: function (iBody) {
iBody.find('#btnSubmit').click();
initGrid();
}
});
}
子html(表单)写法:
- form包括的部分就是表单部分
- layui-form-item:表单项
html<button id="btnSubmit" class="layui-btn" lay-submit lay-filter="add">提交</button>
:隐藏的按钮,利用这个执行提交
<form id="form" class="layui-form" style="margin-top: 25px">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label label-required">选择工序</label>
<div class="layui-input-inline">
<input type="hidden" name="Id" id="Id" />
<input type="hidden" name="ConfigId" id="ConfigId" />
<input type="hidden" name="ProductPartNo" id="ProductPartNo" />
<select class="select2 layui-input-inline" lay-ignore name="StationCode" lay-verify="required" id="StationCode" style="width: 130px"></select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label label-required">工序顺序号</label>
<div class="layui-input-inline">
<input type="number" name="Step" id="Step" lay-verify="required" placeholder="请输入序号" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label label-required">校验工站</label>
<div class="layui-input-inline">
<select lay-ignore name="CheckStations" class="select2" id="CheckStations" multiple="multiple" style="width: 514px;" ></select>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">选项</label>
<div class="layui-input-block">
<input type="checkbox" lay-skin="primary" name="IsAllowJump" value="true" title="允许跳站" checked>
<input type="checkbox" lay-skin="primary" name="IsAllowRepeat" value="true" title="允许重复作业">
<input type="checkbox" lay-skin="primary" name="IsTranshipStation" value="true" title="中转工序">
<input type="checkbox" lay-skin="primary" name="IsGenerateCodeStation" value="true" title="生成国标码工序">
<input type="checkbox" lay-skin="primary" name="IsEntrance" value="true" title="入口工序">
</div>
</div>
</div>
<div class="layui-form-item" style="display: none">
<div class="layui-input-block">
<button id="btnSubmit" class="layui-btn" lay-submit lay-filter="add">提交</button>
</div>
</div>
</form>
子js写法:
- $(“#form”).formSerialize(data):通过formSerialize反序列化到每一个控件
- form.on(‘submit(add)’, function (form):通过submit(add)事件进行表单提交
<script type="text/javascript">
layui.use(['element', 'form', 'laydate', 'layer'], function () {
var form = layui.form;
var element = layui.element;
var laydate = layui.laydate;
laydate.render({
});
var configId = $.getQueryString("configId");
$("#ConfigId").val(configId);
$("#StationCode").bindSelect({
type: "POST",
url: "/param/unitProcedure/getParentCode?configId=" + configId
});
$("#CheckStations").bindSelect({
type: "POST",
url: "/param/unitProcedure/getParentCode?configId=" + configId,
title: '请选择校验工序'
});
var configId = $.getQueryString("configId");
$("#ConfigId").val(configId);
var primaryKey = $.getQueryString("primaryKey");
var productPartNo = $.getQueryString("productPartNo");
$("#ProductPartNo").val(productPartNo);
if (primaryKey) {
$.ajax({
url: "/param/route/getForm",
data: { primaryKey: primaryKey,
configId: configId },
type: "post",
dataType: "json",
async: false,
success: function (data) {
//在这里反序列化
$("#form").formSerialize(data);
$("#ConfigId").val(configId);
}
});
}
form.render();
form.on('submit(add)', function (form) {
var type = $('input[name="IsParent"]:checked').val();
var parentIsNull = $("#Pid").val() == null;
form.field.Criterion = $("#CheckStations").val().join();
$.formSubmit({
url: "/param/route/form",
data: form.field
});
return false;
});
});
</script>
webapi
传参
无论是内建类型,还是实体类型,统一传参类型为dynamic,由方法自身来解释
data本身必须是Json字符串,而不是实体
using Newtonsoft.Json;
[ApiController]
[Route("[controller]")]
public class apiController : ControllerBase
{
//实体
public class test
{
public string name = "";
public int id = 1;
public string[]? nickName;
}
public string dynamicPara(dynamic data)
{
test objdyn = JsonConvert.DeserializeObject<test>(Convert.ToString(data));
string d = objdyn.name;
return d;
}
}
用apipost测试,接口可以正常解释参数
Project
Entity
声明模型,包括DTO(数据传输对象),表格实体等等
Utility
相关的库,包括日志
杂记
菜单获取
1、先找出类型为菜单且图层为0的项
c => c.Type == ModuleType.Menu && c.Layer == 0
Menu = 2
2、再找出类型为子菜单且图层为1,父Id为上一层id的项
c => c.Type == ModuleType.SubMenu && c.Layer == 1 && c.ParentId == item.Id
3、只要第二行的url和图标和名称
Select(c => new LayChildNavbar() { href = c.Url, icon = c.Icon, title = c.Name })
url
- Controller类要在前面加上,才能找到对应视图
[HiddenApi]
[Area("Param")]
- 所有需要路由的方法都要加上路由地址,js才能调用
[Route("/param/plc/index")]
[HiddenApi]
[Area("Param")]
public class PLCController : Controller
{
[Route("/param/plc/index")]
[HttpGet]
public IActionResult Index()
{
return View();
}
}
分页表格
Js写法,需要注意params即便为空,也要写上
function initGrid() {
paging.init({
url: '/param/plc/getlist',
elem: '#content',
tempElem: '#contentTpl',
singleSelected: true, //单选
params: {
},
pageConfig: {
elem: 'paged',
pageSize: 10,
},
success: function () {
}
});
}
C#写法,要带pageIndex和pageSize,一个是页码,一个是一页显示的行数
[Route("/param/plc/getlist")]
[HttpPost]
public ActionResult GetList(int pageIndex, int pageSize)
{
try
{
int totalCount = 0;
var pageData = paramPLCLogic.GetList(pageIndex, pageSize, ref totalCount);
var result = new LayPadding<ParamPLC>()
{
result = true,
msg = "success",
list = pageData,
count = totalCount
};
return Content(result.ToJson());
}
catch(Exception E)
{
return Content(new LayPadding<ParamPLC>()
{
result = false,
msg = E.Message,
list = new List<ParamPLC>(),
count = 0
}.ToJson());
}
}
报错
分表标识
现象:“中文提示 : 需要在分表字段加上属性[SplitFieldAttribute]
English Message : [SplitFieldAttribute] need to be added to the table field”
原因:没指定[splitfield]
解决:在CreateTime上面标注[splitfield]属性
在webservice的形参不能设置datacontract
会出现labview无法找到返回的data
"…"doesnothaveanattribute route. ActionMethodsOnController
现象:如图,报错"…"doesnothaveanattribute route. ActionMethodsOnController
原因:指定了[ApiController]属性的类,存在没指定[Route]属性的方法
解决:所有方法都要指定[Route]属性
btn_task is not define
现象:在点击网页按钮后,控制台出现如题异常
原因:btn_task用了layeropen,url没写对,一定要有参数,不能直接调用
解决:url要写,并且要带参数
表单提交后提示无信息的异常抖动窗口
现象:如题
原因:提交时候post的地址,有多个
解决:保证只有一个就行
控制器中的形参拿不到视图中Form.Field的值
现象:如题
原因:AskTargetParam 的成员变量没实现get和set
解决:AskTargetParam 里面的成员变量实现get和set,如下
public class AskTargetParam
{
//任务号
public string taskId { get; set; }
//产品条码
public string productCode { get; set; }
//指当前物料的类型
public string productType { get; set; }
//起点
public string start { get; set; }
//区域点
public string region { get; set; }
}