- IDE为VS 2022社区版(英文版),DotNet Core版本为.NET 8
创建项目
- 打开VS,依次点击工具栏文件按钮->新建->项目,搜索框输入"ASP.NET Core",语言选择"C#",在筛选结果中选择"ASP.NET Core Web App (Model-View-Controller)",点击"Next"按钮。
- 填写自己的Project Name项目名称,如:DotNet.NewLife.Cube,点击Next下一步
选择".NET 8.0"版本,模板选择`Web 应用程序`,最后点击Create创建。
- 创建完之后,项目结构如下。
安装并应用NewLife.Cube.Core
- 右键点击项目中依赖项->点击管理NuGet程序包->搜索框输入"NewLife.Cube.Core",选中搜索结果,点击安装。
- Program.cs文件修改如下。注意从.NET 6开始Startup.cs默认没有了。
using NewLife.Cube;
//using NewLife.Cube.WebMiddleware;
//using NewLife.Cube.AdminLTE;
//using NewLife.Cube.ElementUI;
//using NewLife.Cube.LayuiAdmin;
//using NewLife.Cube.Metronic;
//using NewLife.Cube.Tabler;
//using NewLife.Cube.ElementUI;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// 引入星尘,设置监控中间件
//var star = builder.Services.AddStardust(null);
//TracerMiddleware.Tracer = star?.Tracer;
// 启用接口响应压缩
builder.Services.AddResponseCompression();
builder.Services.AddControllersWithViews();
// 启用魔方
builder.Services.AddCube();
var app = builder.Build();
// 加载魔方UI
//app.UseAdminLTE(app.Environment);
//app.UseTabler(app.Environment);
//app.UseMetronic(app.Environment);
//app.UseElementUI(app.Environment);
//app.UseMetronic8(app.Environment);
//app.UseLayuiAdmin(app.Environment);
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// 使用魔方
app.UseCube(app.Environment);
// 使用魔方首页
app.UseCubeHome();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
- 编译项目,项目上点击鼠标右键 > View查看,在浏览器中查看,运行魔方平台。
- 这时候会出现这个SSL证书的提示,选择Yes就对了
- 一切顺利的话,就能看到魔方的登录页面,默认账号密码都是`admin`,登录进去,可看到内置的控制器。注意:初始化运行需要下载静态资源和驱动,生成菜单,所以出现异常或者页面样式不对,都是正常现象,稍等或重新运行项目即可。
- 预览的时候可能的报错信息
那么可以看到控制台的报错:
那么也可以看日志或者按F5,会看到具体的报错。
System.DllNotFoundException: 'Unable to load DLL 'SQLite.Interop.dll' or one of its dependencies: 找不到指定的模块。 (0x8007007E)'
需要到bin目录下找到Plugins删除,重新F5会自动重新下载。
添加自己的页面
新建区域
- 首先新建区域School,手动创建文件夹Areas/School,在此文件夹创建区域类SchoolArea,填入以下内容。
using NewLife.Cube;
using NewLife;
using System.ComponentModel;
namespace DotNet.NewLife.Cube.Areas.School
{
[DisplayName("教务系统")]
public class SchoolArea : AreaBase
{
public SchoolArea() : base(nameof(SchoolArea).TrimEnd("Area")) { }
static SchoolArea() => RegisterArea<SchoolArea>();
}
}
新建实体
- 新建数据库实体类,参考数据中间件NewLife.XCode教程。新建文件夹Areas/School/Models,将实体类放在此文件夹,具体内容参考这里 。
- 我使用了XCodeTool.exe + Model.xml (具体用法参考这里),没用码神工具。
新建控制器
- 新建文件夹Areas/School/Controllers,新建ClassController、StudentController两个控制器,分别填入以下内容。
using Microsoft.AspNetCore.Mvc;
using NewLife.Cube;
using NewLife.Log;
using NewLife.School.Entity;
using NewLife.Web;
using System.ComponentModel;
using System.Reflection;
using System.Security.Claims;
using XCode.Membership;
namespace DotNet.NewLife.Cube.Areas.School.Controllers
{
[SchoolArea]
[DisplayName("班级")]
public class ClassController : EntityController<Class, ClassModel>
{
private readonly ITracer _tracer;
public ClassController(IServiceProvider provider)
{
PageSetting.EnableTableDoubleClick = true;
_tracer = provider?.GetService<ITracer>();
}
protected override IEnumerable<Class> Search(Pager p)
{
using var span = _tracer?.NewSpan(nameof(Search), p);
var id = p["Id"].ToInt(-1);
if (id > 0)
{
var entity = Class.FindById(id);
return entity == null ? new List<Class>() : new List<Class> { entity };
}
var start = p["dtStart"].ToDateTime();
var end = p["dtEnd"].ToDateTime();
return Class.Search(start, end, p["Q"], p);
}
}
}
using Microsoft.AspNetCore.Mvc;
using NewLife.Cube.ViewModels;
using NewLife.Cube;
using System.ComponentModel;
using System.Reflection;
using XCode.Membership;
using NewLife.School.Entity;
using NewLife.Web;
namespace DotNet.NewLife.Cube.Areas.School.Controllers
{
[SchoolArea]
[DisplayName("学生")]
public class StudentController : EntityController<Student, StudentModel>
{
static StudentController()
{
ListFields.RemoveField("CreateUserID");
ListFields.RemoveField("UpdateUserID");
//FormFields
}
protected override Student Find(Object key)
{
return base.Find(key);
}
protected override IEnumerable<Student> Search(Pager p)
{
return base.Search(p);
//var classid = p["classid"].ToInt();
//return Student.Search(null,p);
}
public override ActionResult Index(Pager p = null)
{
return base.Index(p);
}
}
}
页面修改
- 此时运行,一切正常,可看到如下页面。
- 如果要修改页面,那么直接在对应位置建立对应视图文件即可自动覆盖。详细可覆盖文件参考这里。
- 比如修改学生主页,则新建文件夹Areas/School/Views/Student/,新建文件_List_Data.cshtml。填入以下内容。
@using NewLife;
@using NewLife.Cube
@using NewLife.Web;
@using XCode;
@using XCode.Configuration;
@using XCode.Membership
@{
var fact = ViewBag.Factory as IEntityFactory;
var page = ViewBag.Page as Pager;
var fields = ViewBag.Fields as List<FieldItem>;
}
<table class="table table-bordered table-hover table-striped table-condensed">
<thead>
<tr>
<th class="text-center hidden-md hidden-sm hidden-xs"><a href="@Html.Raw(page.GetSortUrl("ID"))">编号</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("ClassID"))">班级2</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("Name"))">名称3</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("Sex"))">性别4</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("Age"))">年龄5</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("Mobile"))">手机</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("Address"))">地址</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("CreateTime"))">创建时间</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("CreateIP"))">创建地址</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("UpdateTime"))">更新时间</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("UpdateIP"))">更新地址</a></th>
<th class="text-center"><a href="@Html.Raw(page.GetSortUrl("Remark"))">备注</a></th>
@if (this.Has(PermissionFlags.Detail, PermissionFlags.Update, PermissionFlags.Delete))
{
<th class="text-center">操作</th>
}
</tr>
</thead>
<tbody>
@foreach (var entity in Model)
{
<tr>
<td class="text-center hidden-md hidden-sm hidden-xs">@entity.ID</td>
<td>@entity.ClassName</td>
<td>@entity.Name</td>
<td class="text-center">@entity.Sex</td>
<td class="text-right">@entity.Age.ToString("n0")</td>
<td>@entity.Mobile</td>
<td>@entity.Address</td>
<td>@Utility.ToFullString(entity.CreateTime, "")</td>
<td>@entity.CreateIP</td>
<td>@Utility.ToFullString(entity.UpdateTime, "")</td>
<td>@entity.UpdateIP</td>
<td>@entity.Remark</td>
@if (this.Has(PermissionFlags.Detail, PermissionFlags.Update, PermissionFlags.Delete))
{
<td class="text-center">
@await Html.PartialAsync("_List_Data_Action", (Object)entity)
</td>
}
</tr>
}
</tbody>
</table>
- 修改后页面如下。其他页面均可按照此方式进行覆盖。