(强力推荐!)记录将 DevExpress 的Blazor Demo (Github示例)改造为通用的 Admin 后台,并加入XAF的 安全用户、角色、权限

       DevExpress 是一家提供微软技术的配套全面解决方案的软件商,其最新试用产品提供了: Blazor 控件、XAF 开发框架、其中有可单独使用的 以角色为基础的用户授权开权限控制API包。

        (1) 演示示例地址: https://demos.devexpress.com/blazor/。参考官方解释 Online Demos    https://docs.devexpress.com/Blazor/401058/demos#run-demos-locally

              在GitHub 的源代码 

       (2) 上述示例没有用户身份验证与角色权限等内容, 但官方有单独的多个身份验证与授权示例:(参考)  How to: Use the Integrated Mode of the Security System in Non-XAF Applications

          源码地址: https://github.com/DevExpress-Examples/XAF_Security_E4908

          其中:  Blazor Server App  是 面向 Blazor 服务器端的类型,     地址:https://github.com/DevExpress-Examples/XAF_Security_E4908/tree/master/XPO/ASP.NetCore/Blazor.ServerSide?utm_source=DevExpress&utm_medium=Website&utm_campaign=XAF&utm_content=XAF_Security_NonXAF_Series_6_Blazor_ServerSide

                本Blog 记录改造Blazor演示示例的过程, 首先清理 BlazorDemo.ServerSide 项目,然后将 身份验证项目,整合成一个 后台Admin系统,并充分利用 DevExpress 的Blazor 控件。

 

 一、 清理 BlazorDemo.ServerSide 项目

         本服务端演示解决方案,实际包含两个项目, 其中启动项目是:  BlazorDemo.ServerSide ,引用了库项目: BlazorDemo.ServerSide.Core  (默认命令空间,设定为: BlazorDemo)。

        1、 启动项目  BlazorDemo.ServerSide, Properties文件夹的(launchSettings.json)要引入,系统隐藏了。

        3、ConnectionStrings.json   独立,可以设置数据库连接字符串;

        4、Startup.ServerSide.cs  +  HostingStartupBase.cs , 是 StartUp类,配置服务与中间件,需要清理服务;

               清理库Core 项目后,才能开始,主要是清理服务注册。

               2个 Startup.XXX  注册了 5个 DBContext,多个 DataProvider ,注释掉(与库项目相关文件一起,参考后续!)

        5、Pages 文件夹下的  _Host.cshtml  文件

               注释掉:<environment include="Wasm.AspNetCoreHosted">  环境组件相关部分。              

        6、Utils 件夹下的 DataSourceLoadOptions.cs  保持。

        7、Controllers 件夹  (移动到库项目 / 或 排除

              有 2个控制器,一个用于 NwindController 用于演示 GRID 获得大数据量;另一个 UploadController 用于演示 上传文件。两者都有菜单项演示。

              在库项目中,编译时 复制了整个文件夹及文件。(在 项目的 .CSProj 文件中,删除 复制有关的 ItemGroup)

              运作: 排除(删除)NwindController  或 UploadController  或者将整个文件夹移动到 库项目,取消 编译时复制。

        8、DataProviders 件夹 (排除/删除)

              在库项目中,也有对应的DataProviders 件夹(主要是 接口), 并在 HostingStartupBase.cs 注册为服务。

              排除/删除,与对应的库项目。

 

二、 清理 BlazorDemo.ServerSide.Core 项目  (重点)

(一) 全局文件

       1、App.razor 、_Imports.razor  

       2、Startup.Reporting.cs   定义了静态类 ReportingHostingStartup

             在启动项目的 Startup.ServerSide.cs 文件的最后 有语句使用其方法:

              ReportingHostingStartup.Configure(builder);  

       3、Utils.cs  工具静态类, 用于获取静态资产及连接字符串。 

       4、DemoServiceCollectionExtensions.cs  扩展 “服务集合 IServiceCollection” 

             (1)用于在服务集合中,将 Services 文件夹中定义的 DataService,注册到服务容器中。

             (2)配置 文档元数据   IDocumentMetadataCollection

 (二)  Shared 文件夹

        1、MainLayout.razor  是App 选择的默认。  DefaultLayout="@(typeof(MainLayout))

              1)注释掉  :Free Trial  连接;

              2) 修改版权申明:  

                   <div class="version">版本: @DemoVersion.Version</div>
                   <div class="copyright">
                         <span>版权 &copy; 2000-</span><span>@DateTimeNowYear</span>
                         XXXX 开发
                   </div>

             3)前面启动项目 appsettings.json  可以加入一个  "dxversion": "[X.X]"  ,会影响版本号的第四位;

        2、NavMenuFactoryComponent.cs 、NavMenu.razor、NavMenuReporting

              [  NavMenuFactoryComponent  中,可以依据配置属性(.ShowOnlyReporting),开启不同的菜单,可注释掉开启(NavMenuReporting

                  // if (Configuration.ShowOnlyReporting) {
                       // builder.OpenComponent<NavMenuReporting>(0);
                       // builder.CloseComponent(); }   ]

                  此项可选,如果保留,将 “NavMenuReporting” 中 菜单项注释掉。

         3、排除 Pages 文件夹下的所有  演示页面。

              1) NavMenu  关闭所有 菜单项(根、子): 

                         即  DxTreeView 组件中的 <Nodes> 内容: @foreach 整个内容。

                     将 “NavMenuReporting” 中 菜单项注释掉。即 DxTreeView 中 Nodes 的内容。  且注释掉不注入 DemoReportSource所有菜单项的数据源!)

              2)排除 Pages 文件夹下的所有  演示页面。不留一个

                    由于 Pages 文件夹是系统保留,所以,根Pages 不能取消。

              ------------------  至此,没有菜单与页面了。------------------------

 

         4、关闭与报表相关的功能,涉及以下文件与目录文件夹

                Startup.Reporting.cs 、Shared 文件夹NavMenuReporting.razor、

                Services文件夹 \  ReportFactory.cs + DemoReportStorageWebExtension.cs +ReportingCustomConfigurationProvider.cs

                Reports 文件夹 \ 所有演示页面与文件,可以全部删除

              1)  注释掉: _Imports.razor      的  @*@using BlazorDemo.Reports*@         

       【  2)  排除掉:  Shared 文件夹  NavMenuReporting.razor   报表相关页面。------  如上可以保留。只注释掉菜单。]  

              3)  排除 :    Services 文件夹下: ReportFactory.cs   (定义 DemoReportSource,接口 IDemoReportSource ,定义 ReportInfo), 同时

                      排除: Services 文件夹下    DemoReportStorageWebExtension.cs , 继续 :DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension

                                  官方文档  “Create a Blazor Reporting (JavaScript-Based) Application”  有涉及 ReportStorageWebExtension 的应用报表设计器等)。

                      排除ReportingCustomConfigurationProvider.cs

              4)  排除  Startup.Reporting.cs 

                                  类StartupFilter 方法ConfigureApp 的   app.UseDevExpressBlazorReporting();

                                  Startup.Reporting.cs  中 ,      ReportingHostingStartup  的 静态方法,

                               //services.AddSingleton<IDemoReportSource, DemoReportSource>();

                               //services.AddScoped<ReportStorageWebExtension, DemoReportStorageWebExtension>();

                     同时,注释掉:启动项目 Startup.ServerSide.cs 中的  ReportingHostingStartup.Configure(builder);   ----- 其引用了Startup.Reporting.cs。

              5) 排除掉:Reports 文件夹(所有报表设计文件)。

             ------------------  至此,没有报表了。------------------------ 

(三) 关闭数据服务,涉及多个文件及文件夹

            1、DemoServiceCollectionExtensions.cs 扩展了服务注册(.AddDemoServices),增加了:7 项数据服务 XXDataService;

                  库项目 Services 文件夹下,含有7项服务的定义,(另外3项 是报表有关,已排除)

                  services.AddScoped<WeatherForecastService>();
                  services.AddScoped<ProductsFlatService>(); //;;
                  services.AddScoped<RentInfoDataService>();//
                  services.AddScoped<ContosoRetailDataService>(); //
                  services.AddScoped<NwindDataService>();//
                  services.AddScoped<IssuesDataService>();//
                  services.AddScoped<WorldcitiesDataService>();//     

            2、上述 7服务,引用了 Startup.ServerSide.cs 、HostingStartupBase.cs 中注册的  数据提供者与数据上下文 

                 (保留) services.AddDemoServices();   ---- 数据服务,定义在 DemoServiceCollectionExtensions.cs 中

                 services.AddDbContextFactory<NorthwindContext>、<IssuesContext>、<WorldcitiesContext>

                 <RentInfoContext>、<ContosoRetailContext>     ---- 数据上下文  ,定义在 启动项目 \ DataProviders \EntityFramework  文件夹下

                 //  13个接口及实现                                                ----  数据提供者 ,12个接口定义在 库项目 \DataProviders 文件夹下,

                    实现在 启动项目 \ DataProviders  或 \EntityFramework  文件夹下。                     

                 services.AddSingleton<IContosoRetailDataProvider, ContosoRetailDataProvider>();

                 services.AddSingleton<IRentInfoDataProvider, RentInfoDataProvider>();

                 services.AddSingleton<IProductCategoriesProvider, ProductCategoriesProvider>();
                 services.AddSingleton<ISalesInfoDataProvider, SalesInfoDataProvider>();
                 services.AddSingleton<IFinancialSeriesDataProvider, FinancialSeriesDataProvider>();
                 services.AddSingleton<ICurrencyExchangeDataProvider, UsdJpyDataProvider>();
                 services.AddSingleton<IUsdJpyCsvFileContentProvider, UsdJpyCsvFileContentProvider>();
                 services.AddSingleton<IWeatherSummaryCsvFileContentProvider, WeatherSummaryCsvFileContentProvider>();
                 services.AddSingleton<IWeatherSummaryDataProvider, WeatherSummaryDataProvider>();
                 services.AddSingleton<IIssuesDataProvider, IssuesDataProvider>();
                 services.AddSingleton<IWorldcitiesDataProvider, WorldcitiesDataProvider>();

                 // Editable should be scoped
                 services.AddScoped<INwindDataProvider, NwindDataProvider>();
                 services.AddScoped<IProductsFlatProvider, ProductsFlatProvider>();

         3、DbContex数据实体定义

              定义在 库项目 \Data  文件夹下。

         4、数据库与数据文件

              定义在 库项目 \DataSources  文件夹下。 共有  7个 db 文件,1个 sqlite3 ,2个 csv 文件。

         5、启动项目 Controllers 文件夹下

              NwindController (2个文件) 此文件引用了  NorthwindContext 。

         ---------------------------------------

         6、排除或注释过程

               注释启动项目的服务注册(DemoServiceCollectionExtensions 7项、Startup 共18项 dbconext、dataprovider);

               按序排除 库项目文件夹:Services、DataProviders(也包括启动项目)、Data、DataSources;

               排除启动项目 Controllers 文件夹下 2个 NwindController 

               保留 库项目文件夹 DataProviders 下  IDataProvider.cs 文件,或移动到  Shared 文件夹下,其  DataProviderAccessAreaContainer 引用了接口。 

(四) 与 DocumentMetadata 相关内容 (排除)

         1、DemoServiceCollectionExtensions.cs 文件中

                  services.AddDocumentMetadata(ConfigureMetadata); 

                           ---- 扩展方法 定义在 DocumentMetadata\ DocumentMetadata.AspNetCore.cs 中。

                  static void ConfigureMetadata(IServiceProvider sp, IDocumentMetadataCollection metadataCollection) {

                                    sp.GetService<DemoConfiguration>().ConfigureMetadata(metadataCollection);                     }

          2、Configuration 文件夹下  DemoConfiguration.cs  2个方法

                 public virtual void ConfigureMetadata(IDocumentMetadataCollection metadataCollection)

                static void ConfigurePage(IDocumentMetadataCollection metadataCollection, DemoPageBase page, string title, string titleFormat)                    

          3、Shared\ThemeSwitcher文件夹下  ThemeSwitcher.razor 

                 [Inject]

                 IDocumentMetadataService DocumentMetadataService { get; set; }

                 DocumentMetadataService.Update(  Action<IDocumentMetadataBuilder> )

                 Update 方法涉及的范围太大,暂保留。可将 DocumentMetadata  文件夹名称 修改为:DocMetadata。

          4、另一种选择

                ThemeSwitcher 中使用的DocumentMetadataService.Update 方法,主要是选择样式后,更新 Style。

                       DocumentMetadataService.Update((m) => {
                            m.StyleSheet("currentThemeCss", Themes.GetThemeCssUrl(theme));
                            m.StyleSheet("currentThemeCodeCss", Themes.GetThemeCodeCssUrl(theme));     });

                       关闭(删除0)上述语句,就不能够更新选择的样式。

                 另一选择就是:手工修改选择的样式,将你想选择的样式所属的Css文件(wwwroot\css\switcher-resources\themes\XXXX),

                                             复制(Copy)到 wwwroot\css\switcher-resources\themes\default 。

                 如果手工操作,可以排除(删除)Shared\ThemeSwitcher,  以及整个 DocumentMetadata 文件夹及相关内容。

                                         注释 MainLayout.razor 的选择图标,以及ThemeSwitcher 组件;

                                         注释 CommServiceExt.cs  中的 services.AddDocumentMetadata(ConfigureMetadata)  、static void ConfigureMetadata。

                                         注释 DemoConfiguration.cs 中的 public virtual void ConfigureMetadata、static void ConfigurePage。

                   ---------  这样就没有主题选择了-------------------------

(五)  Configuration 与 Shared 文件夹 

       1、DemoProductInfo 

            (1) Index.razor 首页有涉及  DemoProductInfo 的内容, 注释掉。

                 RenderFragment<DemoProductInfo> DemoProduct = (info) =>  整个委托;

                 @foreach(var info in Configuration.Products)  ....   整个循环。

             (2) 排除  DemoProductInfo.cs    

                   同时注释掉  DemoConfiguration.cs 、DemoConfigurationData.cs  相关的对 类 DemoProductInfo 的引用语句。

              (3)  排除 Configuration\DemoFeedback.cs  与  Shared\ DemoFeedbackPanel.razor + DemoFeedbackPanel.razor.css

      2、MainLayout.razor 中 Search 与 DemoVersion

            (1) 注释  MainLayout.razor 中的 

                       <DemoSearchEditor @bind-SearchString="@SearchString" /> 

                       <DemoSearchResultList SearchString="@SearchString" SearchResults="@SearchResults" />

                      <div class="info-wrapper">    </div> 包含的内容。

                     注释掉 :@code {  } 中的 相关的函数:public string SearchString、SearchResults、UpdateSearchResults()。

             (2)Startup.ServerSide.cs  注释:  services.AddSingleton<IDemoVersion, DemoVersion>(...)  以及 MainLayout.razor中的注入引用。

             (3)相应排除:Shared\ DemoSearchEditor.razor  、DemoSearchResultList.razor、

                      Configuration \ DemoVersion.cs   、DemoSearchAgregator.cs、DemoSearchHelper.cs、DemoSearchModel.cs、DemoSearchResult.cs

             (4)注释掉  DemoConfiguration.cs、DemoConfigurationData.cs  中的引用类 

      3、MainLayout.razor 中的 DemoModalBackdrop

            注释掉 :if(!_isDesktop) {<DemoModalBackdrop Shown="@ModalBackgroundShown" ShownChanged="@ModalBackdropShownChanged" />

            排除:DemoModalBackdrop.razor  、DemoMobileContent.razor、DemoMobileContent.razor.css。

      4、排除:

            DataProviderAccessArea.razor、DataProviderAccessAreaContainer.razor、DataProviderAccessAreaContainer.razor.cs

       5、排除:  IDataProvider.cs、IFrameLayout.razor

       6、排除: Shared 文件夹下:CodeSnippet、OptionComponents、PageNavigation  三个文件夹及文件。

       7、特别排除: 

                    Shared 文件夹下  DemoPageSectionComponent.razor、DemoPageSectionParameters.cs、

                                                  DemoResizableContent.razor、DemoResizableContent.razor.css

                   Configuration文件夹下  DemoPage.cs、DemoPageSection.cs、DemoPageSectionCodeFile.cs、DemoPageSectionCodeProcessor.cs

                   修改调整 DemoConfiguration.cs 及 DemoConfigurationData.cs  对 DemoPage 等的引用与函数;

                   修改调整 Shared \ DemoBreadcrumbs.razor  对 DemoPage 等的引用与函数。

        8、排除  Configuration文件夹下 DemoPageLayout.razor

              以及  Shared 文件夹下 Error.razor、_Imports.razor

        9、修改 NavMenuFactoryComponent.cs ,仅保留 导航菜单 NavMenu,取消 报表菜单 NavMenuReporting 

              排除 :NavMenuReporting.razor 

       10、清理 主题 DemoTheme 

               排除并删除 : Bootswatch Themes ,保留 DevExpress Themes  以及  Default 四个。

                排除并删除 wwwroot\css\switcher-resources\themes  文件夹下相关文件。

              *********************  最简解决方案 !!! *********************** 

       

 

三、文件夹名称、默认命令空间名称、项目名称、程序集名称 统一调整(难点)

        其中: 文件夹名称、命令空间名称 调整,会涉及很多文件,需要慎重! 

(一)  项目名称、程序集名称 调整 

            库项目名称修改,会影响启动项目中的引用项目的名称

(二) 项目所属文件夹名称” 调整

        *、文件夹名称” 改变,会影响 “文件夹”下引用的资源文件路径,主要是:.CSHtml 、.Razor 文件,具体如下:

        1、启动项目的 _Host.cshtml

              <link rel="prefetch" href="_content/BlazorDemo/css/scroll-view.css" as="style">

              <link rel="stylesheet" href="_content/BlazorDemo/css/dx-demo.css">

              <link rel="stylesheet" href="_content/BlazorDemo/css/dx-demo-pages.css">

              <script type="text/javascript" src="_content/BlazorDemo/bootstrapper.js" defer></script>

               下列几个,引用href 中含有:_content、_framework,    AHCorp.ServerSide 是(启动项目的)默认程序集名称。

              <link rel="stylesheet" href="_content/DevExpress.Blazor/dx-blazor.css">

              <link rel="stylesheet" href="_content/DevExpress.Blazor.RichEdit/dx-richedit.css">

              <link rel="preload" href="_framework/blazor.server.js" as="script">
              <link href="BlazorDemo.ServerSide.styles.css" rel="stylesheet">     ------ 比较特别,参考:https://blog.csdn.net/xhydongda/article/details/117081960

               说明1:  _framework  _content 来定位 css/js 。 在 Server 的 _Host.cshtml 或 WebAssembly 的 index.html 文件中,可以引用 Blazor 组件库里面的css或js资源。

               [ 在 WebAssembly  wwwroot/index.html 文件中,你会发现有一行 <script src="_framework/blazor.webassembly.js"></script>,_framework 指向的是编译后生成的 bin\Debug\netX.X\wwwroot\_framework 文件夹。根据你使用的组件,可以向 index.html 添加<link href="_content/Z.Blazor.Diagrams/style.css" rel="stylesheet" />,这里面的 _content 指向引用的组件库 XXBlazor 下面的 wwwroot 目录。]

               说明2: BlazorDemo.ServerSide.styles.css  其中“BlazorDemo.ServerSide” 是项目名称,项目编译后的 Obj \XX...\scopedcss\bundle 文件夹下的css文件名

        2、库项目 Shared

              BrowserNotSupported.razor              :<img class="mt-2 mr-4" src="_content/BlazorDemo/images/Sad.svg"   

             DemoThemesConfiguration.cs           :return $"_content/BlazorDemo/css/switcher-resources/themes/{theme.Name}/bootstrap.min.css";

             DxScrollView.razor                              :Src="_content/BlazorDemo/lib/scroll-view.js" 

             MainLayout.razor                                : Src="_content/BlazorDemo/lib/page-helper.js"

 

(三)默认命令空间名称 调整

         1、启动项目的“默认命令空间名称”,保持与项目名称一致

                 首先,重新命令 启动项目的名称,相应地会 调整启动项目的  程序集名称、默认命令空间名称, 两者保持一致;

                 然后,将启动项目下,有关文件(.CS)的命令空间名称,相应地进行修改调整,以与项目名称或默认命令空间名称,相一致。 

                主要文件是:

                      Program.cs、HostingStartupBase.cs、Startup.ServerSide.cs、\Utils\DataSourceLoadOptions.cs  几个。

          2、库项目的 默认命令空间名称 调整

               1)Configuration 文件夹

                     此文件夹下所有.CS 文件的命令空间为:namespace  XX默认命令空间.Configuration  ,进行相应的调整修改。

               2)Shared、Pages 文件夹

                     Shared文件夹下所有 .CS 文件的命令空间依据调整后的新“命令空间名称”进行修改。主要是:

                          DemoScriptLoader.cs、  NavMenuFactoryComponent.cs

               3) _Imports.razor、App.razor、CommServiceExt.cs、Utils.cs

                      _Imports.razor、App.razor ,调整修改 相应引用的命令空间。

                      CommServiceExt.cs、Utils.cs , 调整修改 类定义的命令空间。

               4) 所有文件,如果引用的类的命令空间修改了,相应进行调整。

 

四、将  Security System  的配置代码集成到上述启动项目

        (参考)  How to: Use the Integrated Mode of the Security System in Non-XAF Applications

          源码地址: https://github.com/DevExpress-Examples/XAF_Security_E4908

          其中:  Blazor Server App  是 面向 Blazor 服务器端的类型,     地址:https://github.com/DevExpress-Examples/XAF_Security_E4908/tree/master/XPO/ASP.NetCore/Blazor.ServerSide?utm_source=DevExpress&utm_medium=Website&utm_campaign=XAF&utm_content=XAF_Security_NonXAF_Series_6_Blazor_ServerSide

 

1、将 Security System 的Startup的服务注入,迁移到 库项目

     1)安装  DevExpress.ExpressApp.Security.Xpo 包

     2)安装  DevExpress.Persistent.BaseImpl 包

     3)复制 Helpers 文件夹 到库项目,包括2个文件:SecurityProvider.cs、XpoDataStoreProviderService.cs

     4)在CommServiceExt.cs 文件的 AddDemoServices 方法中 增加 “服务注册”

           (或者 启动项目的 Startup 的 ConfigureServices 方法中 增加)

           services.AddSession(); 

           services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                        .AddCookie( );

           services.AddCusXafSecurity().AddCusSecuredTypes(typeof(ECUser), typeof(ECRole));

    5) 在启动项目的 Startup 的 Configure 方法中 增加 几个中间件 ,注意与原有中间件的顺序。

           app.UseSession();

           app.UseDefaultFiles();   //参考补充

           ......

           app.UseRouting();

           app.UseAuthentication();

          app.UseEndpoints(endpoints => {
                           endpoints.MapBlazorHub();
                           endpoints.MapFallbackToPage("/_Host");   });                   //增加 

       6)复制 到 Pages文件夹: Login.cshtml 、Login.cshtml.cs、LogOut.cshtml、LogOut.cshtml.cs

       7)_Imports.razor 中增加:

              @using Microsoft.AspNetCore.Components.Authorization  

       8)依据迁移项目,修改 库项目 App.razor           

             增加 @inject NavigationManager NavigationManager

             代替 <Found/> 内的  <RouteView RouteData="@routeData" DefaultLayout="@(typeof(MainLayout))" /> 为:   

                    <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">

                        <NotAuthorized>
                                @{ string returnUrl = "~/" + NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
                                 NavigationManager.NavigateTo($"Login?returnUrl={returnUrl}", forceLoad: true); }
                        </NotAuthorized>
                    </AuthorizeRouteView>

            代替 <NotFound> 内:

                      <LayoutView Layout="@(typeof(MainLayout))">
                            <p>Sorry, there's nothing at this address.</p>
                      </LayoutView>    为:

               <CascadingAuthenticationState>
                      <LayoutView Layout="@typeof(MainLayout)">
                           <p>Sorry, there's nothing at this address.</p>
                      </LayoutView>
               </CascadingAuthenticationState>

 

 

 

              

 

posted @ 2021-07-27 11:08  eccorp  阅读(1272)  评论(0编辑  收藏  举报