├── .gitattributes ├── .github └── workflows │ └── vale.yml ├── .gitignore ├── AspNetCore.Reporting.Angular ├── .gitignore ├── Areas │ └── Identity │ │ ├── IdentityHostingStartup.cs │ │ └── Pages │ │ ├── Account │ │ ├── Login.cshtml │ │ ├── Login.cshtml.cs │ │ └── _ViewImports.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml ├── AspNetCore.Reporting.Angular.csproj ├── AspNetCore.Reporting.Angular.sln ├── ClientApp │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── angular.json │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.e2e.json │ ├── package.json │ ├── src │ │ ├── api-authorization │ │ │ ├── api-authorization.constants.ts │ │ │ ├── api-authorization.module.spec.ts │ │ │ ├── api-authorization.module.ts │ │ │ ├── authorize.guard.spec.ts │ │ │ ├── authorize.guard.ts │ │ │ ├── authorize.interceptor.spec.ts │ │ │ ├── authorize.interceptor.ts │ │ │ ├── authorize.service.spec.ts │ │ │ ├── authorize.service.ts │ │ │ ├── login-menu │ │ │ │ ├── login-menu.component.css │ │ │ │ ├── login-menu.component.html │ │ │ │ ├── login-menu.component.spec.ts │ │ │ │ └── login-menu.component.ts │ │ │ ├── login │ │ │ │ ├── login.component.css │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.spec.ts │ │ │ │ └── login.component.ts │ │ │ └── logout │ │ │ │ ├── logout.component.css │ │ │ │ ├── logout.component.html │ │ │ │ ├── logout.component.spec.ts │ │ │ │ └── logout.component.ts │ │ ├── app │ │ │ ├── app.component.html │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── app.server.module.ts │ │ │ ├── home │ │ │ │ ├── home.component.html │ │ │ │ └── home.component.ts │ │ │ ├── nav-menu │ │ │ │ ├── nav-menu.component.css │ │ │ │ ├── nav-menu.component.html │ │ │ │ └── nav-menu.component.ts │ │ │ ├── report-list │ │ │ │ ├── report.list.component.html │ │ │ │ └── report.list.component.ts │ │ │ ├── reportdesigner │ │ │ │ ├── report-designer.html │ │ │ │ └── report-designer.ts │ │ │ └── reportviewer │ │ │ │ ├── report-viewer.html │ │ │ │ └── report-viewer.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── index.html │ │ ├── karma.conf.js │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tslint.json ├── Controllers │ ├── CustomAngularReportingControllers.cs │ ├── OidcConfigurationController.cs │ ├── ReportDesignerController.cs │ └── ReportListController.cs ├── Data │ ├── DbInitializer.cs │ ├── Migrations │ │ └── SchoolDbContextModelSnapshot.cs │ └── SchoolDbContext.cs ├── Database │ ├── application.db │ ├── nwind.db │ └── nwind.json ├── Models │ └── ApplicationUser.cs ├── Pages │ ├── Error.cshtml │ ├── Error.cshtml.cs │ ├── Shared │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ └── _ValidationScriptsPartial.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ ├── launchSettings.json │ ├── serviceDependencies.json │ └── serviceDependencies.local.json ├── Reports │ ├── CourseListReport.Designer.cs │ ├── CourseListReport.cs │ ├── CourseListReport.resx │ ├── MyEnrollmentsReport.Designer.cs │ ├── MyEnrollmentsReport.cs │ ├── MyEnrollmentsReport.resx │ └── ReportsFactory.cs ├── Services │ ├── CourseListReportRepository.cs │ ├── CustomObjectDataSourceWizardTypeProvider.cs │ └── MyEnrollmentsReportRepository.cs ├── Startup.cs ├── ViewerStorages │ ├── Documents │ │ └── 803b2d4fd99079e7b7752d60b30a62b3 │ │ │ ├── Document │ │ │ └── 0.prnx │ │ │ ├── ExportInfo │ │ │ ├── 0.prnx │ │ │ └── 1.prnx │ │ │ ├── Metadata │ │ │ ├── 0.prnx │ │ │ ├── 1.prnx │ │ │ └── 2.prnx │ │ │ └── Page │ │ │ └── 0.prnx │ └── Reports │ │ └── d3b31846ec8db38d248596e6af17c743 │ │ ├── reportDetails.json │ │ └── virtualReport.repx ├── appsettings.Development.json └── appsettings.json ├── AspNetCore.Reporting.Common ├── AspNetCore.Reporting.Common.csproj ├── Data │ ├── Course.cs │ ├── DbDefaultsGenerator.cs │ ├── Enrollment.cs │ ├── IReportEntityProvider.cs │ ├── IStudentEntityProvider.cs │ ├── ReportEntity.cs │ └── StudentIdentity.cs ├── Models │ ├── CourseModel.cs │ ├── EnrollmentDetailsModel.cs │ ├── ExportResult.cs │ ├── LoginRequest.cs │ ├── LoginResponse.cs │ ├── LoginScreenModel.cs │ ├── ReportingControlModel.cs │ └── StudentDetailsModel.cs └── Services │ ├── IAuthenticatiedUserService.cs │ ├── ObjectDataSourceInjector.cs │ ├── Reporting │ ├── CustomExceptionHandlers.cs │ ├── CustomObjectDataSourceWizardServices.cs │ ├── CustomPreviewReportCustomizationService.cs │ ├── CustomReportProvider.cs │ ├── CustomSqlDataConnectionProviderFactory.cs │ ├── CustomSqlDataSourceWizardConnectionStringsProvider.cs │ ├── DocumentViewerAuthorizationService.cs │ ├── EFCoreReportStorageWebExtension.cs │ └── ReportingLoggerService.cs │ ├── ScopedDbContextProvider.cs │ ├── ServiceRegistrator.cs │ └── UserService.cs ├── AspNetCore.Reporting.MVC ├── .gitignore ├── Areas │ └── Identity │ │ └── Pages │ │ └── _ViewStart.cshtml ├── AspNetCore.Reporting.MVC.csproj ├── AspNetCore.Reporting.MVC.sln ├── Controllers │ ├── AccountController.cs │ ├── CustomMVCReportingControllers.cs │ └── HomeController.cs ├── Data │ ├── DbInitializer.cs │ └── SchoolDbContext.cs ├── Database │ ├── application.db │ ├── application.db-shm │ ├── application.db-wal │ ├── nwind.db │ └── nwind.json ├── Migrations │ ├── 20200909232101_InitialCreate.Designer.cs │ ├── 20200909232101_InitialCreate.cs │ └── SchoolDbContextModelSnapshot.cs ├── Models │ ├── CourseModel.cs │ ├── CustomDesignerModel.cs │ ├── CustomViewerModel.cs │ ├── EnrollmentDetailsModel.cs │ ├── ErrorViewModel.cs │ ├── ExportResult.cs │ ├── LoginRequest.cs │ ├── LoginResponse.cs │ ├── LoginScreenModel.cs │ ├── ReportingControlModel.cs │ └── StudentDetailsModel.cs ├── Program.cs ├── Properties │ ├── launchSettings.json │ ├── serviceDependencies.json │ └── serviceDependencies.local.json ├── Reports │ ├── CourseListReport.Designer.cs │ ├── CourseListReport.cs │ ├── CourseListReport.resx │ ├── MyEnrollmentsReport.Designer.cs │ ├── MyEnrollmentsReport.cs │ ├── MyEnrollmentsReport.resx │ └── ReportsFactory.cs ├── Services │ ├── CourseListReportRepository.cs │ ├── CustomObjectDataSourceWizardTypeProvider.cs │ ├── CustomStudentsUserStore.cs │ └── MyEnrollmentsReportRepository.cs ├── Startup.cs ├── Views │ ├── Account │ │ └── Login.cshtml │ ├── Home │ │ ├── DesignReport.cshtml │ │ ├── DisplayReport.cshtml │ │ ├── Index.cshtml │ │ └── Privacy.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ └── _ValidationScriptsPartial.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── appsettings.Development.json ├── appsettings.json ├── bundleconfig.json ├── libman.json ├── package.json └── wwwroot │ ├── css │ ├── ace │ │ ├── ambiance-1.png │ │ ├── ambiance-2.png │ │ ├── ambiance-3.png │ │ ├── chrome-1.png │ │ ├── chrome-2.png │ │ ├── cloud9_day-1.png │ │ ├── cloud9_day-2.png │ │ ├── cloud9_night-1.png │ │ ├── cloud9_night-2.png │ │ ├── cloud9_night_low_color-1.png │ │ ├── cloud9_night_low_color-2.png │ │ ├── clouds-1.png │ │ ├── clouds-2.png │ │ ├── clouds_midnight-1.png │ │ ├── clouds_midnight-2.png │ │ ├── cobalt-1.png │ │ ├── cobalt-2.png │ │ ├── crimson_editor-1.png │ │ ├── crimson_editor-2.png │ │ ├── dawn-1.png │ │ ├── dawn-2.png │ │ ├── dracula-1.png │ │ ├── dracula-2.png │ │ ├── dreamweaver-1.png │ │ ├── dreamweaver-2.png │ │ ├── eclipse-1.png │ │ ├── eclipse-2.png │ │ ├── github-1.png │ │ ├── github-2.png │ │ ├── github_dark-1.png │ │ ├── github_dark-2.png │ │ ├── github_light_default-1.png │ │ ├── github_light_default-2.png │ │ ├── gob-1.png │ │ ├── gob-2.png │ │ ├── gruvbox-1.png │ │ ├── gruvbox-2.png │ │ ├── gruvbox_dark_hard-1.png │ │ ├── gruvbox_light_hard-1.png │ │ ├── gruvbox_light_hard-2.png │ │ ├── idle_fingers-1.png │ │ ├── idle_fingers-2.png │ │ ├── iplastic-1.png │ │ ├── iplastic-2.png │ │ ├── iplastic-3.png │ │ ├── katzenmilch-1.png │ │ ├── katzenmilch-2.png │ │ ├── kr_theme-1.png │ │ ├── kr_theme-2.png │ │ ├── kuroir-1.png │ │ ├── kuroir-2.png │ │ ├── main-1.png │ │ ├── main-10.png │ │ ├── main-10.svg │ │ ├── main-11.png │ │ ├── main-11.svg │ │ ├── main-12.png │ │ ├── main-12.svg │ │ ├── main-13.png │ │ ├── main-14.png │ │ ├── main-15.png │ │ ├── main-16.png │ │ ├── main-17.png │ │ ├── main-18.png │ │ ├── main-19.png │ │ ├── main-2.png │ │ ├── main-20.png │ │ ├── main-21.png │ │ ├── main-22.png │ │ ├── main-22.svg │ │ ├── main-23.png │ │ ├── main-24.png │ │ ├── main-25.svg │ │ ├── main-26.png │ │ ├── main-3.png │ │ ├── main-4.png │ │ ├── main-5.png │ │ ├── main-5.svg │ │ ├── main-6.png │ │ ├── main-6.svg │ │ ├── main-7.png │ │ ├── main-7.svg │ │ ├── main-8.png │ │ ├── main-8.svg │ │ ├── main-9.png │ │ ├── main-9.svg │ │ ├── merbivore-1.png │ │ ├── merbivore-2.png │ │ ├── merbivore_soft-1.png │ │ ├── merbivore_soft-2.png │ │ ├── mono_industrial-1.png │ │ ├── mono_industrial-2.png │ │ ├── monokai-1.png │ │ ├── monokai-2.png │ │ ├── one_dark-1.png │ │ ├── one_dark-2.png │ │ ├── pastel_on_dark-1.png │ │ ├── pastel_on_dark-2.png │ │ ├── solarized_dark-1.png │ │ ├── solarized_dark-2.png │ │ ├── solarized_light-1.png │ │ ├── solarized_light-2.png │ │ ├── sqlserver-1.png │ │ ├── sqlserver-2.png │ │ ├── terminal-1.png │ │ ├── terminal-2.png │ │ ├── textmate-1.png │ │ ├── textmate-2.png │ │ ├── tomorrow-1.png │ │ ├── tomorrow-2.png │ │ ├── tomorrow_night-1.png │ │ ├── tomorrow_night-2.png │ │ ├── tomorrow_night_blue-1.png │ │ ├── tomorrow_night_blue-2.png │ │ ├── tomorrow_night_bright-1.png │ │ ├── tomorrow_night_bright-2.png │ │ ├── tomorrow_night_eighties-1.png │ │ ├── tomorrow_night_eighties-2.png │ │ ├── twilight-1.png │ │ ├── twilight-2.png │ │ ├── vibrant_ink-1.png │ │ ├── vibrant_ink-2.png │ │ ├── xcode-1.png │ │ └── xcode-2.png │ └── site.css │ ├── js │ └── site.js │ └── localization │ └── devextreme │ └── de.json ├── CODEOWNERS ├── Images ├── screenshot.png └── skeleton.png ├── LICENSE ├── Readme.md └── config.json /.gitattributes: -------------------------------------------------------------------------------- 1 | VB/* linguist-vendored 2 | scripts linguist-vendored 3 | *.css linguist-detectable=false 4 | *.aff linguist-detectable=false -------------------------------------------------------------------------------- /.github/workflows/vale.yml: -------------------------------------------------------------------------------- 1 | name: vale-validation 2 | on: 3 | pull_request: 4 | paths: 5 | - README.md 6 | - readme.md 7 | - Readme.md 8 | 9 | jobs: 10 | vale: 11 | name: runner / vale 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: clone repo 15 | uses: actions/checkout@v4 16 | - name: clone vale-styles repo 17 | uses: actions/checkout@v4 18 | with: 19 | repository: DevExpress/vale-styles 20 | path: vale-styles 21 | ssh-key: ${{ secrets.VALE_STYLES_ACCESS_KEY }} 22 | - name: copy vale rules to the root repo 23 | run: shopt -s dotglob && cp -r ./vale-styles/vale/* . 24 | - name: vale linter check 25 | uses: DevExpress/vale-action@reviewdog 26 | with: 27 | files: '["README.md", "readme.md", "Readme.md"]' 28 | fail_on_error: true 29 | filter_mode: nofilter 30 | reporter: github-check 31 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Areas/Identity/IdentityHostingStartup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | 3 | [assembly: HostingStartup(typeof(AspNetCore.Reporting.Angular.Areas.Identity.IdentityHostingStartup))] 4 | namespace AspNetCore.Reporting.Angular.Areas.Identity 5 | { 6 | public class IdentityHostingStartup : IHostingStartup 7 | { 8 | public void Configure(IWebHostBuilder builder) 9 | { 10 | builder.ConfigureServices((context, services) => { 11 | }); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Areas/Identity/Pages/Account/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AspNetCore.Reporting.Angular.Areas.Identity.Pages.Account -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Areas/Identity/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using AspNetCore.Reporting.Angular.Areas.Identity 3 | @using AspNetCore.Reporting.Angular.Areas.Identity.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | @using AspNetCore.Reporting.Common.Data 6 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 |  2 | @{ 3 | Layout = "/Pages/Shared/_Layout.cshtml"; 4 | } 5 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/AspNetCore.Reporting.Angular.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30503.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Reporting.Angular", "AspNetCore.Reporting.Angular.csproj", "{E14C26B4-A5A1-4E27-9487-4132F4060DBB}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Reporting.Common", "..\AspNetCore.Reporting.Common\AspNetCore.Reporting.Common.csproj", "{3DF36EF4-69E2-4692-BFE0-94E5994BAA96}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {E14C26B4-A5A1-4E27-9487-4132F4060DBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {E14C26B4-A5A1-4E27-9487-4132F4060DBB}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {E14C26B4-A5A1-4E27-9487-4132F4060DBB}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {E14C26B4-A5A1-4E27-9487-4132F4060DBB}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {3DF36EF4-69E2-4692-BFE0-94E5994BAA96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3DF36EF4-69E2-4692-BFE0-94E5994BAA96}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3DF36EF4-69E2-4692-BFE0-94E5994BAA96}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3DF36EF4-69E2-4692-BFE0-94E5994BAA96}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {017E63F0-A3FA-43FB-B50E-8F33BA19E2A3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /dist-server 6 | /tmp 7 | /.angular 8 | /out-tsc 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # IDEs and editors 14 | /.idea 15 | .project 16 | .classpath 17 | .c9/ 18 | *.launch 19 | .settings/ 20 | *.sublime-workspace 21 | 22 | # IDE - VSCode 23 | .vscode/* 24 | !.vscode/settings.json 25 | !.vscode/tasks.json 26 | !.vscode/launch.json 27 | !.vscode/extensions.json 28 | 29 | # misc 30 | /.sass-cache 31 | /connect.lock 32 | /coverage 33 | /libpeerconnection.log 34 | npm-debug.log 35 | yarn-error.log 36 | testem.log 37 | /typings 38 | 39 | # System Files 40 | .DS_Store 41 | Thumbs.db 42 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/README.md: -------------------------------------------------------------------------------- 1 | # AspNetCore.Reporting.Angular 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require("jasmine-spec-reporter"); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: ["./src/**/*.e2e-spec.ts"], 9 | capabilities: { 10 | browserName: "chrome" 11 | }, 12 | directConnect: true, 13 | baseUrl: "http://localhost:4200/", 14 | framework: "jasmine", 15 | jasmineNodeOpts: { 16 | showColors: true, 17 | defaultTimeoutInterval: 30000, 18 | print: function() {} 19 | }, 20 | onPrepare() { 21 | require("ts-node").register({ 22 | project: require("path").join(__dirname, "./tsconfig.e2e.json") 23 | }); 24 | jasmine 25 | .getEnv() 26 | .addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getMainHeading()).toEqual('Hello, world!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getMainHeading() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aspnetcore.reporting.angular", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "build:ssr": "ng run aspnetcore.reporting.angular:server:dev", 9 | "watch": "ng build --watch --configuration development", 10 | "test": "ng test" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^17.0.0", 15 | "@angular/common": "^17.0.0", 16 | "@angular/compiler": "^17.0.0", 17 | "@angular/core": "^17.0.0", 18 | "@angular/forms": "^17.0.0", 19 | "@angular/platform-browser": "^17.0.0", 20 | "@angular/platform-browser-dynamic": "^17.0.0", 21 | "@angular/platform-server": "^17.0.0", 22 | "@angular/router": "^17.0.0", 23 | "devextreme": "24.2-stable", 24 | "devextreme-angular": "24.2-stable", 25 | "@devexpress/analytics-core": "24.2-stable", 26 | "devexpress-reporting-angular": "24.2-stable", 27 | "devexpress-richedit": "24.2-stable", 28 | "bootstrap": "^5.1.3", 29 | "jquery": "^3.6.0", 30 | "oidc-client": "^1.11.5", 31 | "popper.js": "^1.16.0", 32 | "run-script-os": "^1.1.6", 33 | "rxjs": "~7.8.0", 34 | "tslib": "^2.3.0", 35 | "zone.js": "~0.14.2" 36 | }, 37 | "devDependencies": { 38 | "@angular-devkit/build-angular": "^17.0.0", 39 | "@angular/cli": "^17.0.0", 40 | "@angular/compiler-cli": "^17.0.0", 41 | "@angular/language-service": "^17.0.0", 42 | "@types/jasmine": "~5.1.0", 43 | "@types/node": "^18.11.9", 44 | "jasmine-core": "~5.1.0", 45 | "karma": "~6.4.0", 46 | "karma-chrome-launcher": "~3.2.0", 47 | "karma-coverage": "~2.2.0", 48 | "karma-jasmine": "~5.1.0", 49 | "karma-jasmine-html-reporter": "~2.1.0", 50 | "typescript": "~5.2.2" 51 | }, 52 | "overrides": { 53 | "autoprefixer": "10.4.5" 54 | }, 55 | "optionalDependencies": {} 56 | } 57 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/api-authorization.constants.ts: -------------------------------------------------------------------------------- 1 | export const ApplicationName = 'AspNetCore.Reporting.Angular'; 2 | 3 | export const ReturnUrlType = 'returnUrl'; 4 | 5 | export const QueryParameterNames = { 6 | ReturnUrl: ReturnUrlType, 7 | Message: 'message' 8 | }; 9 | 10 | export const LogoutActions = { 11 | LogoutCallback: 'logout-callback', 12 | Logout: 'logout', 13 | LoggedOut: 'logged-out' 14 | }; 15 | 16 | export const LoginActions = { 17 | Login: 'login', 18 | LoginCallback: 'login-callback', 19 | LoginFailed: 'login-failed', 20 | Profile: 'profile', 21 | Register: 'register' 22 | }; 23 | 24 | let applicationPaths: ApplicationPathsType = { 25 | DefaultLoginRedirectPath: '/', 26 | ApiAuthorizationClientConfigurationUrl: `/_configuration/${ApplicationName}`, 27 | Login: `authentication/${LoginActions.Login}`, 28 | LoginFailed: `authentication/${LoginActions.LoginFailed}`, 29 | LoginCallback: `authentication/${LoginActions.LoginCallback}`, 30 | Register: `authentication/${LoginActions.Register}`, 31 | Profile: `authentication/${LoginActions.Profile}`, 32 | LogOut: `authentication/${LogoutActions.Logout}`, 33 | LoggedOut: `authentication/${LogoutActions.LoggedOut}`, 34 | LogOutCallback: `authentication/${LogoutActions.LogoutCallback}`, 35 | LoginPathComponents: [], 36 | LoginFailedPathComponents: [], 37 | LoginCallbackPathComponents: [], 38 | RegisterPathComponents: [], 39 | ProfilePathComponents: [], 40 | LogOutPathComponents: [], 41 | LoggedOutPathComponents: [], 42 | LogOutCallbackPathComponents: [], 43 | IdentityRegisterPath: '/Identity/Account/Register', 44 | IdentityManagePath: '/Identity/Account/Manage' 45 | }; 46 | 47 | applicationPaths = { 48 | ...applicationPaths, 49 | LoginPathComponents: applicationPaths.Login.split('/'), 50 | LoginFailedPathComponents: applicationPaths.LoginFailed.split('/'), 51 | RegisterPathComponents: applicationPaths.Register.split('/'), 52 | ProfilePathComponents: applicationPaths.Profile.split('/'), 53 | LogOutPathComponents: applicationPaths.LogOut.split('/'), 54 | LoggedOutPathComponents: applicationPaths.LoggedOut.split('/'), 55 | LogOutCallbackPathComponents: applicationPaths.LogOutCallback.split('/') 56 | }; 57 | 58 | interface ApplicationPathsType { 59 | readonly DefaultLoginRedirectPath: string; 60 | readonly ApiAuthorizationClientConfigurationUrl: string; 61 | readonly Login: string; 62 | readonly LoginFailed: string; 63 | readonly LoginCallback: string; 64 | readonly Register: string; 65 | readonly Profile: string; 66 | readonly LogOut: string; 67 | readonly LoggedOut: string; 68 | readonly LogOutCallback: string; 69 | readonly LoginPathComponents: string []; 70 | readonly LoginFailedPathComponents: string []; 71 | readonly LoginCallbackPathComponents: string []; 72 | readonly RegisterPathComponents: string []; 73 | readonly ProfilePathComponents: string []; 74 | readonly LogOutPathComponents: string []; 75 | readonly LoggedOutPathComponents: string []; 76 | readonly LogOutCallbackPathComponents: string []; 77 | readonly IdentityRegisterPath: string; 78 | readonly IdentityManagePath: string; 79 | } 80 | 81 | export const ApplicationPaths: ApplicationPathsType = applicationPaths; 82 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/api-authorization.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { ApiAuthorizationModule } from './api-authorization.module'; 2 | 3 | describe('ApiAuthorizationModule', () => { 4 | let apiAuthorizationModule: ApiAuthorizationModule; 5 | 6 | beforeEach(() => { 7 | apiAuthorizationModule = new ApiAuthorizationModule(); 8 | }); 9 | 10 | it('should create an instance', () => { 11 | expect(apiAuthorizationModule).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/api-authorization.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { LoginMenuComponent } from './login-menu/login-menu.component'; 4 | import { LoginComponent } from './login/login.component'; 5 | import { LogoutComponent } from './logout/logout.component'; 6 | import { RouterModule } from '@angular/router'; 7 | import { ApplicationPaths } from './api-authorization.constants'; 8 | import { HttpClientModule } from '@angular/common/http'; 9 | 10 | @NgModule({ 11 | imports: [ 12 | CommonModule, 13 | HttpClientModule, 14 | RouterModule.forChild( 15 | [ 16 | { path: ApplicationPaths.Register, component: LoginComponent }, 17 | { path: ApplicationPaths.Profile, component: LoginComponent }, 18 | { path: ApplicationPaths.Login, component: LoginComponent }, 19 | { path: ApplicationPaths.LoginFailed, component: LoginComponent }, 20 | { path: ApplicationPaths.LoginCallback, component: LoginComponent }, 21 | { path: ApplicationPaths.LogOut, component: LogoutComponent }, 22 | { path: ApplicationPaths.LoggedOut, component: LogoutComponent }, 23 | { path: ApplicationPaths.LogOutCallback, component: LogoutComponent } 24 | ] 25 | ) 26 | ], 27 | declarations: [LoginMenuComponent, LoginComponent, LogoutComponent], 28 | exports: [LoginMenuComponent, LoginComponent, LogoutComponent] 29 | }) 30 | export class ApiAuthorizationModule { } 31 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/authorize.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AuthorizeGuard } from './authorize.guard'; 4 | 5 | describe('AuthorizeGuard', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AuthorizeGuard] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([AuthorizeGuard], (guard: AuthorizeGuard) => { 13 | expect(guard).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/authorize.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { AuthorizeService } from './authorize.service'; 5 | import { tap } from 'rxjs/operators'; 6 | import { ApplicationPaths, QueryParameterNames } from './api-authorization.constants'; 7 | 8 | @Injectable({ 9 | providedIn: 'root' 10 | }) 11 | export class AuthorizeGuard implements CanActivate { 12 | constructor(private authorize: AuthorizeService, private router: Router) { 13 | } 14 | canActivate( 15 | _next: ActivatedRouteSnapshot, 16 | state: RouterStateSnapshot): Observable | Promise | boolean { 17 | return this.authorize.isAuthenticated() 18 | .pipe(tap(isAuthenticated => this.handleAuthorization(isAuthenticated, state))); 19 | } 20 | 21 | private handleAuthorization(isAuthenticated: boolean, state: RouterStateSnapshot) { 22 | if (!isAuthenticated) { 23 | this.router.navigate(ApplicationPaths.LoginPathComponents, { 24 | queryParams: { 25 | [QueryParameterNames.ReturnUrl]: state.url 26 | } 27 | }); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/authorize.interceptor.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AuthorizeInterceptor } from './authorize.interceptor'; 4 | 5 | describe('AuthorizeInterceptor', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AuthorizeInterceptor] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([AuthorizeInterceptor], (service: AuthorizeInterceptor) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/authorize.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | import { AuthorizeService } from './authorize.service'; 5 | import { mergeMap } from 'rxjs/operators'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class AuthorizeInterceptor implements HttpInterceptor { 11 | constructor(private authorize: AuthorizeService) { } 12 | 13 | intercept(req: HttpRequest, next: HttpHandler): Observable> { 14 | return this.authorize.getAccessToken() 15 | .pipe(mergeMap(token => this.processRequestWithToken(token, req, next))); 16 | } 17 | 18 | // Checks if there is an access_token available in the authorize service 19 | // and adds it to the request in case it's targeted at the same origin as the 20 | // single page application. 21 | private processRequestWithToken(token: string | null, req: HttpRequest, next: HttpHandler) { 22 | if (!!token && this.isSameOriginUrl(req)) { 23 | req = req.clone({ 24 | setHeaders: { 25 | Authorization: `Bearer ${token}` 26 | } 27 | }); 28 | } 29 | 30 | return next.handle(req); 31 | } 32 | 33 | private isSameOriginUrl(req: any) { 34 | // It's an absolute url with the same origin. 35 | if (req.url.startsWith(`${window.location.origin}/`)) { 36 | return true; 37 | } 38 | 39 | // It's a protocol relative url with the same origin. 40 | // For example: //www.example.com/api/Products 41 | if (req.url.startsWith(`//${window.location.host}/`)) { 42 | return true; 43 | } 44 | 45 | // It's a relative url like /api/Products 46 | if (/^\/[^\/].*/.test(req.url)) { 47 | return true; 48 | } 49 | 50 | // It's an absolute or protocol relative url that 51 | // doesn't have the same origin. 52 | return false; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/authorize.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AuthorizeService } from './authorize.service'; 4 | 5 | describe('AuthorizeService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AuthorizeService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([AuthorizeService], (service: AuthorizeService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login-menu/login-menu.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login-menu/login-menu.component.css -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login-menu/login-menu.component.html: -------------------------------------------------------------------------------- 1 | 9 | 17 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login-menu/login-menu.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginMenuComponent } from './login-menu.component'; 4 | 5 | describe('LoginMenuComponent', () => { 6 | let component: LoginMenuComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginMenuComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginMenuComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login-menu/login-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AuthorizeService } from '../authorize.service'; 3 | import { Observable } from 'rxjs'; 4 | import { map, tap } from 'rxjs/operators'; 5 | 6 | @Component({ 7 | selector: 'app-login-menu', 8 | templateUrl: './login-menu.component.html', 9 | styleUrls: ['./login-menu.component.css'] 10 | }) 11 | export class LoginMenuComponent implements OnInit { 12 | public isAuthenticated!: Observable; 13 | public userName!: Observable; 14 | 15 | constructor(private authorizeService: AuthorizeService) { } 16 | 17 | ngOnInit() { 18 | this.isAuthenticated = this.authorizeService.isAuthenticated(); 19 | this.userName = this.authorizeService.getUser().pipe(map(u => u && u.name)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login/login.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login/login.component.css -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login/login.component.html: -------------------------------------------------------------------------------- 1 |

{{ message | async }}

-------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/logout/logout.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/logout/logout.component.css -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/logout/logout.component.html: -------------------------------------------------------------------------------- 1 |

{{ message | async }}

-------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/api-authorization/logout/logout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LogoutComponent } from './logout.component'; 4 | 5 | describe('LogoutComponent', () => { 6 | let component: LogoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LogoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LogoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
-------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html' 6 | }) 7 | export class AppComponent { 8 | title = 'app'; 9 | } 10 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 5 | import { RouterModule } from '@angular/router'; 6 | 7 | import { AppComponent } from './app.component'; 8 | import { NavMenuComponent } from './nav-menu/nav-menu.component'; 9 | import { DxReportViewerModule, DxReportDesignerModule } from 'devexpress-reporting-angular'; 10 | import { HomeComponent } from './home/home.component'; 11 | import { ReportListComponent } from './report-list/report.list.component'; 12 | import { ApiAuthorizationModule } from 'src/api-authorization/api-authorization.module'; 13 | import { AuthorizeGuard } from 'src/api-authorization/authorize.guard'; 14 | import { AuthorizeInterceptor } from 'src/api-authorization/authorize.interceptor'; 15 | import { ReportDesignerComponent } from './reportdesigner/report-designer'; 16 | import { ReportViewerComponent } from './reportviewer/report-viewer'; 17 | 18 | @NgModule({ 19 | declarations: [ 20 | AppComponent, 21 | NavMenuComponent, 22 | HomeComponent, 23 | ReportViewerComponent, 24 | ReportDesignerComponent, 25 | ReportListComponent 26 | ], 27 | imports: [ 28 | BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), 29 | HttpClientModule, 30 | FormsModule, 31 | DxReportViewerModule, 32 | DxReportDesignerModule, 33 | ApiAuthorizationModule, 34 | RouterModule.forRoot([ 35 | { path: '', component: HomeComponent, pathMatch: 'full' }, 36 | { path: 'designer', component: ReportDesignerComponent, canActivate: [AuthorizeGuard] }, 37 | { path: 'viewer', component: ReportViewerComponent, canActivate: [AuthorizeGuard] }, 38 | { path: 'report-list', component: ReportListComponent, canActivate: [AuthorizeGuard]}, 39 | ]) 40 | ], 41 | providers: [ 42 | { provide: HTTP_INTERCEPTORS, useClass: AuthorizeInterceptor, multi: true } 43 | ], 44 | bootstrap: [AppComponent] 45 | }) 46 | export class AppModule { } 47 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/app.server.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { ServerModule } from '@angular/platform-server'; 3 | import { AppComponent } from './app.component'; 4 | import { AppModule } from './app.module'; 5 | 6 | @NgModule({ 7 | imports: [AppModule, ServerModule], 8 | bootstrap: [AppComponent] 9 | }) 10 | export class AppServerModule { } 11 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |

Hello, world!

2 |

Welcome to your new single-page application, built with:

3 | 8 |

To help you get started, we've also set up:

9 |
    10 |
  • Client-side navigation. For example, click Counter then Back to return here.
  • 11 |
  • Angular CLI integration. In development mode, there's no need to run ng serve. It runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file.
  • 12 |
  • Efficient production builds. In production mode, development-time features are disabled, and your dotnet publish configuration automatically invokes ng build to produce minified, ahead-of-time compiled JavaScript files.
  • 13 |
14 |

The ClientApp subdirectory is a standard Angular CLI application. If you open a command prompt in that directory, you can run any ng command (e.g., ng test), or use npm to install extra packages into it.

15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: './home.component.html', 6 | }) 7 | export class HomeComponent { 8 | } 9 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/nav-menu/nav-menu.component.css: -------------------------------------------------------------------------------- 1 | a.navbar-brand { 2 | white-space: normal; 3 | text-align: center; 4 | word-break: break-all; 5 | } 6 | 7 | html { 8 | font-size: 14px; 9 | } 10 | @media (min-width: 768px) { 11 | html { 12 | font-size: 16px; 13 | } 14 | } 15 | 16 | .box-shadow { 17 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 18 | } 19 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/nav-menu/nav-menu.component.html: -------------------------------------------------------------------------------- 1 |
2 | 40 |
41 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/nav-menu/nav-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-nav-menu', 5 | templateUrl: './nav-menu.component.html', 6 | styleUrls: ['./nav-menu.component.css'] 7 | }) 8 | export class NavMenuComponent { 9 | isExpanded = false; 10 | 11 | collapse() { 12 | this.isExpanded = false; 13 | } 14 | 15 | toggle() { 16 | this.isExpanded = !this.isExpanded; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/report-list/report.list.component.html: -------------------------------------------------------------------------------- 1 |

Reports

2 |
    3 |
  • 4 | {{reportItem.title}} 5 |
    6 |
    7 | Show 8 | Edit 9 |
    10 |
    11 |
  • 12 |
13 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/report-list/report.list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | @Component({ 5 | selector: 'report-list-component', 6 | templateUrl: './report.list.component.html' 7 | }) 8 | export class ReportListComponent { 9 | reportList?: ReportItem[]; 10 | constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) { 11 | http.get(baseUrl + 'reportlist').subscribe(result => { 12 | this.reportList = result; 13 | }, error => console.error(error)); 14 | } 15 | } 16 | 17 | interface ReportItem { 18 | id: string; 19 | title: string; 20 | } 21 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/reportdesigner/report-designer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/reportdesigner/report-designer.ts: -------------------------------------------------------------------------------- 1 | import { fetchSetup } from "@devexpress/analytics-core/analytics-utils" 2 | import { Component, Inject, ViewEncapsulation, OnInit } from '@angular/core'; 3 | import { AuthorizeService } from '../../api-authorization/authorize.service'; 4 | import * as ko from 'knockout'; 5 | import { ActivatedRoute } from '@angular/router'; 6 | 7 | @Component({ 8 | selector: 'report-designer', 9 | encapsulation: ViewEncapsulation.None, 10 | templateUrl: './report-designer.html', 11 | styleUrls: [ 12 | "../../../node_modules/ace-builds/css/ace.css", 13 | "../../../node_modules/ace-builds/css/theme/dreamweaver.css", 14 | "../../../node_modules/devextreme/dist/css/dx.material.blue.light.css", 15 | "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css", 16 | "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.material.blue.light.css", 17 | "../../../node_modules/@devexpress/analytics-core/dist/css/dx-querybuilder.css", 18 | "../../../node_modules/devexpress-reporting/dist/css/dx-webdocumentviewer.css", 19 | "../../../node_modules/devexpress-reporting/dist/css/dx-reportdesigner.css" 20 | ] 21 | }) 22 | 23 | export class ReportDesignerComponent implements OnInit { 24 | getDesignerModelAction = "api/ReportDesignerSetup/GetReportDesignerModel"; 25 | get reportUrl() { 26 | return this.koReportUrl(); 27 | }; 28 | set reportUrl(newUrl) { 29 | this.koReportUrl(newUrl); 30 | } 31 | koReportUrl = ko.observable(''); 32 | 33 | constructor(@Inject('BASE_URL') public hostUrl: string, private authorize: AuthorizeService, private activateRoute: ActivatedRoute) { 34 | this.authorize.getAccessToken() 35 | .subscribe(x => { 36 | fetchSetup.fetchSettings = { 37 | headers: { 38 | 'Authorization': 'Bearer ' + x 39 | } 40 | }; 41 | }); 42 | } 43 | 44 | ngOnInit() { 45 | if(this.activateRoute.snapshot.queryParams['reportId']) { 46 | this.reportUrl = this.activateRoute.snapshot.queryParams['reportId']; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/reportviewer/report-viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/app/reportviewer/report-viewer.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { fetchSetup } from '@devexpress/analytics-core/analytics-utils'; 4 | import * as ko from 'knockout'; 5 | import { AuthorizeService } from '../../api-authorization/authorize.service'; 6 | 7 | @Component({ 8 | selector: 'report-viewer', 9 | encapsulation: ViewEncapsulation.None, 10 | templateUrl: './report-viewer.html', 11 | styleUrls: [ 12 | "../../../node_modules/devextreme/dist/css/dx.material.blue.light.css", 13 | "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css", 14 | "../../../node_modules/@devexpress/analytics-core/dist/css/dx-analytics.material.blue.light.css", 15 | "../../../node_modules/devexpress-reporting/dist/css/dx-webdocumentviewer.css" 16 | ] 17 | }) 18 | export class ReportViewerComponent implements OnInit { 19 | get reportUrl() { 20 | return this.koReportUrl(); 21 | }; 22 | set reportUrl(newUrl) { 23 | this.koReportUrl(newUrl); 24 | } 25 | koReportUrl = ko.observable(''); 26 | invokeAction: string = '/DXXRDVAngular'; 27 | 28 | useSameTabExport = true; 29 | useAsynchronousExport = true; 30 | 31 | constructor(@Inject('BASE_URL') public hostUrl: string, private authorize: AuthorizeService, private activateRoute: ActivatedRoute) { 32 | this.authorize.getAccessToken() 33 | .subscribe(x => { 34 | fetchSetup.fetchSettings = { 35 | headers: { 36 | 'Authorization': 'Bearer ' + x 37 | } 38 | }; 39 | }); 40 | } 41 | 42 | ngOnInit() { 43 | if(this.activateRoute.snapshot.queryParams['reportId']) { 44 | this.reportUrl = this.activateRoute.snapshot.queryParams['reportId']; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ClientApp/src/assets/.gitkeep -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AspNetCore.Reporting.Angular 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | export function getBaseUrl() { 8 | return document.getElementsByTagName('base')[0].href; 9 | } 10 | 11 | const providers = [ 12 | { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] } 13 | ]; 14 | 15 | if (environment.production) { 16 | enableProdMode(); 17 | } 18 | 19 | platformBrowserDynamic(providers).bootstrapModule(AppModule) 20 | .catch(err => console.log(err)); 21 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * IE11 requires the following for NgClass support on SVG elements 23 | */ 24 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 25 | 26 | /** 27 | * Web Animations `@angular/platform-browser/animations` 28 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 29 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 30 | */ 31 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 32 | 33 | /** 34 | * By default, zone.js will patch all possible macroTask and DomEvents 35 | * user can disable parts of macroTask/DomEvents patch by setting following flags 36 | * because those flags need to be set before `zone.js` being loaded, and webpack 37 | * will put import in the top of bundle, so user need to create a separate file 38 | * in this directory (for example: zone-flags.ts), and put the following flags 39 | * into that file, and then add the following code before importing zone.js. 40 | * import './zone-flags'; 41 | * 42 | * The flags allowed in zone-flags.ts are listed here. 43 | * 44 | * The following flags will work for all browsers. 45 | * 46 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 47 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 48 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 49 | * 50 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 51 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 52 | * 53 | * (window as any).__Zone_enable_cross_context_check = true; 54 | * 55 | */ 56 | 57 | /*************************************************************************************************** 58 | * Zone JS is required by default for Angular itself. 59 | */ 60 | import 'zone.js'; // Included with Angular CLI. 61 | 62 | 63 | /*************************************************************************************************** 64 | * APPLICATION IMPORTS 65 | */ 66 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | /* Provide sufficient contrast against white background */ 4 | a { 5 | color: #0366d6; 6 | } 7 | 8 | code { 9 | color: #e01a76; 10 | } 11 | 12 | .btn-primary { 13 | color: #fff; 14 | background-color: #1b6ec2; 15 | border-color: #1861ac; 16 | } 17 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [] 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ClientApp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "sourceMap": true, 12 | "declaration": false, 13 | "downlevelIteration": true, 14 | "experimentalDecorators": true, 15 | "moduleResolution": "node", 16 | "importHelpers": true, 17 | "target": "es2017", 18 | "module": "es2020", 19 | "lib": [ 20 | "es2018", 21 | "dom" 22 | ] 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Controllers/CustomAngularReportingControllers.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.AspNetCore.Reporting.QueryBuilder; 2 | using DevExpress.AspNetCore.Reporting.QueryBuilder.Native.Services; 3 | using DevExpress.AspNetCore.Reporting.ReportDesigner; 4 | using DevExpress.AspNetCore.Reporting.ReportDesigner.Native.Services; 5 | using DevExpress.AspNetCore.Reporting.WebDocumentViewer; 6 | using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services; 7 | using Microsoft.AspNetCore.Authorization; 8 | using Microsoft.AspNetCore.Mvc; 9 | 10 | namespace AspNetCore.Reporting.Common.Controllers { 11 | [Authorize] 12 | [Route("DXXRDVAngular")] 13 | public class AngularWebDocumentViewerController : WebDocumentViewerController { 14 | public AngularWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) { 15 | } 16 | 17 | 18 | } 19 | 20 | [Authorize] 21 | [Route("DXXQBAngular")] 22 | public class AngularQueryBuilderController : QueryBuilderController { 23 | public AngularQueryBuilderController(IQueryBuilderMvcControllerService controllerService) : base(controllerService) { 24 | } 25 | } 26 | 27 | 28 | [Route("DXXRDAngular")] 29 | [Authorize] 30 | public class AngularReportDesignerController : ReportDesignerController { 31 | public AngularReportDesignerController(IReportDesignerMvcControllerService controllerService) : base(controllerService) { 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Controllers/OidcConfigurationController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.ApiAuthorization.IdentityServer; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace AspNetCore.Reporting.Angular.Controllers { 6 | public class OidcConfigurationController : Controller { 7 | private readonly ILogger logger; 8 | 9 | public OidcConfigurationController(IClientRequestParametersProvider clientRequestParametersProvider, ILogger _logger) { 10 | ClientRequestParametersProvider = clientRequestParametersProvider; 11 | logger = _logger; 12 | } 13 | 14 | public IClientRequestParametersProvider ClientRequestParametersProvider { get; } 15 | 16 | [HttpGet("_configuration/{clientId}")] 17 | public IActionResult GetClientRequestParameters([FromRoute] string clientId) { 18 | var parameters = ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId); 19 | return Ok(parameters); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Controllers/ReportDesignerController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Mime; 3 | using DevExpress.XtraReports.Web.ReportDesigner; 4 | using DevExpress.XtraReports.Web.ReportDesigner.Services; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AspNetCore.Reporting.Common.Controllers { 9 | [ApiController] 10 | [Authorize] 11 | [Route("api/[controller]")] 12 | public class ReportDesignerSetupController : ControllerBase { 13 | [HttpPost("[action]")] 14 | public object GetReportDesignerModel([FromForm] string reportUrl, 15 | [FromServices] IReportDesignerModelBuilder reportDesignerModel, 16 | [FromServices] IReportDesignerClientSideModelGenerator modelGenerator) { 17 | Dictionary dataSources = new Dictionary(); 18 | //Fill a data source set if needed 19 | reportDesignerModel 20 | .Report(reportUrl) 21 | .DataSources(dataSources) 22 | .DesignerUri("/DXXRDAngular") 23 | .ViewerUri("/DXXRDVAngular") 24 | .QueryBuilderUri("/DXXQBAngular") 25 | .BuildJsonModel(); 26 | var model = reportDesignerModel.BuildModel(); 27 | var modelJson = modelGenerator.GetJsonModelScript(model); 28 | return Content(modelJson, MediaTypeNames.Application.Json); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Controllers/ReportListController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using AspNetCore.Reporting.Angular.Data; 5 | using AspNetCore.Reporting.Common.Models; 6 | using AspNetCore.Reporting.Common.Services; 7 | using Microsoft.AspNetCore.Authorization; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.EntityFrameworkCore; 10 | 11 | namespace AspNetCore.Reporting.Common.Controllers { 12 | [Authorize] 13 | [ApiController] 14 | [Route("[controller]")] 15 | public class ReportListController : ControllerBase { 16 | [HttpGet] 17 | public async Task> Get([FromServices] SchoolDbContext dbContext, [FromServices] IAuthenticatiedUserService userService) { 18 | var reportData = !User.Identity.IsAuthenticated 19 | ? Enumerable.Empty() 20 | : await dbContext 21 | .Reports 22 | .Where(a => a.Student.Id == userService.GetCurrentUserId()) 23 | .Select(a => new ReportingControlModel { 24 | Id = a.ID.ToString(), 25 | Title = string.IsNullOrEmpty(a.DisplayName) ? "Noname Report" : a.DisplayName 26 | }) 27 | .ToListAsync(); 28 | return reportData; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Data/DbInitializer.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using AspNetCore.Reporting.Common.Data; 4 | using AspNetCore.Reporting.Common.Reports; 5 | using DevExpress.XtraReports.UI; 6 | using Microsoft.AspNetCore.Identity; 7 | 8 | namespace AspNetCore.Reporting.Angular.Data { 9 | public static class DbInitializer { 10 | public static void Initialize(SchoolDbContext context, UserManager userManager, ReportsFactory factory) { 11 | context.Database.EnsureDeleted(); 12 | context.Database.EnsureCreated(); 13 | 14 | // Look for any students. 15 | if(context.Students.Any()) { 16 | return; // DB has been seeded 17 | } 18 | 19 | var students = DbDefaultsGenerator.GenerateStudents(userManager); 20 | foreach(StudentIdentity s in students) { 21 | 22 | context.Students.Add(s); 23 | foreach(var report in factory.Reports.Select(a => new { a.Key, Value = a.Value() })) { 24 | context.Reports.Add(new ReportEntity() { 25 | DisplayName = string.IsNullOrEmpty(report.Value.DisplayName) ? report.Key : report.Value.DisplayName, 26 | ReportLayout = ReportToByteArray(report.Value), 27 | Student = s 28 | }); 29 | } 30 | } 31 | context.SaveChanges(); 32 | var courses = DbDefaultsGenerator.GetCourses(); 33 | foreach(Course c in courses) { 34 | context.Courses.Add(c); 35 | } 36 | context.SaveChanges(); 37 | 38 | var enrollments = DbDefaultsGenerator.GetEnrollments(students, courses); 39 | foreach(Enrollment e in enrollments) { 40 | context.Enrollments.Add(e); 41 | } 42 | context.SaveChanges(); 43 | } 44 | 45 | static byte[] ReportToByteArray(XtraReport report) { 46 | using(var memoryStream = new MemoryStream()) { 47 | report.SaveLayoutToXml(memoryStream); 48 | return memoryStream.ToArray(); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Data/SchoolDbContext.cs: -------------------------------------------------------------------------------- 1 | using AspNetCore.Reporting.Common.Data; 2 | using Duende.IdentityServer.EntityFramework.Options; 3 | using Microsoft.AspNetCore.ApiAuthorization.IdentityServer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Options; 6 | 7 | namespace AspNetCore.Reporting.Angular.Data { 8 | public class SchoolDbContext : ApiAuthorizationDbContext, IStudentEntityProvider, IReportEntityProvider { 9 | public SchoolDbContext( 10 | DbContextOptions options, 11 | IOptions operationalStoreOptions) : base(options, operationalStoreOptions) { 12 | } 13 | 14 | public DbSet Courses { get; set; } 15 | public DbSet Enrollments { get; set; } 16 | public DbSet Students { get; set; } 17 | public DbSet Reports { get; set; } 18 | 19 | protected override void OnModelCreating(ModelBuilder modelBuilder) { 20 | base.OnModelCreating(modelBuilder); 21 | modelBuilder.Entity().ToTable("Course"); 22 | modelBuilder.Entity().ToTable("Enrollment"); 23 | modelBuilder.Entity().ToTable("Student"); 24 | modelBuilder.Entity().ToTable("Report"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Database/application.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/Database/application.db -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Database/nwind.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/Database/nwind.db -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Database/nwind.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/Database/nwind.json -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace AspNetCore.Reporting.Angular.Models { 8 | public class ApplicationUser : IdentityUser { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to the Development environment displays detailed information about the error that occurred. 20 |

21 |

22 | The Development environment shouldn't be enabled for deployed applications. 23 | It can result in displaying sensitive information from exceptions to end users. 24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 25 | and restarting the app. 26 |

27 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace AspNetCore.Reporting.Angular.Pages { 11 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 12 | public class ErrorModel : PageModel { 13 | private readonly ILogger _logger; 14 | 15 | public ErrorModel(ILogger logger) { 16 | _logger = logger; 17 | } 18 | 19 | public string RequestId { get; set; } 20 | 21 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 22 | 23 | public void OnGet() { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Hosting 2 | @using Microsoft.AspNetCore.Mvc.ViewEngines 3 | @inject IWebHostEnvironment Environment 4 | @inject ICompositeViewEngine Engine 5 | 6 | 7 | 8 | 9 | 10 | @ViewData["Title"] - AspNetCore.Reporting.Angular 11 | 12 | 13 | 14 | 15 |
16 | 40 |
41 | 42 |
43 |
44 | @RenderBody() 45 |
46 |
47 |
48 |
49 | © 2020 - AspNetCore.Reporting.Angular - Privacy 50 |
51 |
52 | 53 | 54 | 55 | @RenderSection("Scripts", required: false) 56 | 57 | 58 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using AspNetCore.Reporting.Angular.Models; 3 | @using AspNetCore.Reporting.Common.Data; 4 | @inject SignInManager SignInManager 5 | @inject UserManager UserManager 6 | 7 | @{ 8 | string returnUrl = null; 9 | var query = ViewContext.HttpContext.Request.Query; 10 | if (query.ContainsKey("returnUrl")) 11 | { 12 | returnUrl = query["returnUrl"]; 13 | } 14 | } 15 | 16 | 38 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AspNetCore.Reporting.Angular 2 | @namespace AspNetCore.Reporting.Angular.Pages 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AspNetCore.Reporting.Angular.Data; 3 | using AspNetCore.Reporting.Common.Data; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace AspNetCore.Reporting.Angular { 11 | public class Program { 12 | public static void Main(string[] args) { 13 | var host = CreateHostBuilder(args).Build(); 14 | InitializeDb(host); 15 | host.Run(); 16 | } 17 | static void InitializeDb(IHost host) { 18 | using(var scope = host.Services.CreateScope()) { 19 | var services = scope.ServiceProvider; 20 | try { 21 | var context = services.GetRequiredService(); 22 | var userManager = services.GetRequiredService>(); 23 | DbInitializer.Initialize(context, userManager, new Common.Reports.ReportsFactory()); 24 | } catch(Exception exception) { 25 | var logger = services.GetRequiredService>(); 26 | logger.LogError(exception, "An error occurred while seeding the database."); 27 | } 28 | } 29 | } 30 | 31 | public static IHostBuilder CreateHostBuilder(string[] args) => 32 | Host.CreateDefaultBuilder(args) 33 | .ConfigureWebHostDefaults(webBuilder => { 34 | webBuilder.UseStartup(); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:51510", 7 | "sslPort": 44360 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "AspNetCore.Reporting.Angular": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "mssql1": { 4 | "type": "mssql", 5 | "connectionId": "DefaultConnection" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "mssql1": { 4 | "type": "mssql.local", 5 | "connectionId": "DefaultConnection" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Reports/CourseListReport.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.XtraReports.UI; 2 | 3 | namespace AspNetCore.Reporting.Common.Reports { 4 | public partial class CourseListReport : XtraReport { 5 | public CourseListReport() { 6 | InitializeComponent(); 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Reports/MyEnrollmentsReport.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.XtraReports.UI; 2 | 3 | namespace AspNetCore.Reporting.Common.Reports { 4 | public partial class MyEnrollmentsReport : XtraReport { 5 | public MyEnrollmentsReport() { 6 | InitializeComponent(); 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Reports/ReportsFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DevExpress.XtraReports.UI; 4 | 5 | namespace AspNetCore.Reporting.Common.Reports { 6 | public class ReportsFactory { 7 | public Dictionary> Reports { 8 | get { 9 | return new Dictionary>() { 10 | ["Enrollments"] = () => new MyEnrollmentsReport(), 11 | ["CourseList"] = () => new CourseListReport(), 12 | }; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Services/CourseListReportRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AspNetCore.Reporting.Angular.Data; 5 | using AspNetCore.Reporting.Common.Models; 6 | 7 | namespace AspNetCore.Reporting.Common.Services { 8 | public class CourseListReportRepository { 9 | readonly IScopedDbContextProvider scopedDbContextProvider; 10 | 11 | public CourseListReportRepository() { 12 | // We use this parameterless constructor in the Data Source Wizard only, and not for the actual instantiation of the repository object. 13 | throw new NotSupportedException(); 14 | } 15 | 16 | public CourseListReportRepository(IScopedDbContextProvider scopedDbContextProvider) { 17 | this.scopedDbContextProvider = scopedDbContextProvider ?? throw new ArgumentNullException(nameof(scopedDbContextProvider)); 18 | } 19 | 20 | public IList GetCourses() { 21 | using(var dbContextScope = scopedDbContextProvider.GetDbContextScope()) { 22 | var dbContext = dbContextScope.DbContext; 23 | var model = dbContext.Courses.Select(x => 24 | new CourseModel { 25 | CourseID = x.CourseID, 26 | CourseTitle = x.Title 27 | }) 28 | .ToList(); 29 | return model; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Services/CustomObjectDataSourceWizardTypeProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DevExpress.DataAccess.Web; 4 | 5 | namespace AspNetCore.Reporting.Common.Services { 6 | public class CustomObjectDataSourceWizardTypeProvider : IObjectDataSourceWizardTypeProvider { 7 | public IEnumerable GetAvailableTypes(string context) { 8 | return new[] { 9 | typeof(CourseListReportRepository), 10 | typeof(MyEnrollmentsReportRepository) 11 | }; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/Services/MyEnrollmentsReportRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AspNetCore.Reporting.Angular.Data; 5 | using AspNetCore.Reporting.Common.Models; 6 | 7 | namespace AspNetCore.Reporting.Common.Services { 8 | public class MyEnrollmentsReportRepository { 9 | readonly string studentId; 10 | readonly IScopedDbContextProvider scopedDbContextProvider; 11 | 12 | public MyEnrollmentsReportRepository() { 13 | // We use this parameterless constructor in the Data Source Wizard only, and not for the actual instantiation of the repository object. 14 | throw new NotSupportedException(); 15 | } 16 | 17 | public MyEnrollmentsReportRepository(IScopedDbContextProvider scopedDbContextProvider, IAuthenticatiedUserService userService) { 18 | this.scopedDbContextProvider = scopedDbContextProvider ?? throw new ArgumentNullException(nameof(scopedDbContextProvider)); 19 | 20 | // NOTE: the repository ctor is invoked in the context of http request. At this point of execution we have access to context-dependent data, like currentUserId. 21 | // The repository MUST read and store all the required context-dependent values for later use. E.g. notice that we do not store the IUserService (which is context/scope dependent), but read the value of current user and store it. 22 | studentId = userService.GetCurrentUserId(); 23 | } 24 | 25 | public StudentDetailsModel GetStudentDetails() { 26 | using(var dbContextScope = scopedDbContextProvider.GetDbContextScope()) { 27 | var dbContext = dbContextScope.DbContext; 28 | var student = dbContext.Students.Find(studentId); 29 | 30 | var model = new StudentDetailsModel { 31 | StudentID = student.Id, 32 | FirstMidName = student.FirstMidName, 33 | LastName = student.LastName, 34 | EnrollmentDate = student.EnrollmentDate 35 | }; 36 | return model; 37 | } 38 | } 39 | 40 | public IList GetEnrollments() { 41 | using(var dbContextScope = scopedDbContextProvider.GetDbContextScope()) { 42 | var dbContext = dbContextScope.DbContext; 43 | var student = dbContext.Students.Find(studentId); 44 | 45 | dbContext.Entry(student).Collection(x => x.Enrollments).Load(); 46 | student.Enrollments.ToList().ForEach(x => dbContext.Entry(x).Reference(c => c.Course).Load()); 47 | 48 | var enrollmentModels = student.Enrollments.Select(x => 49 | new EnrollmentDetailsModel { 50 | EnrollmentID = x.EnrollmentID, 51 | CourseTitle = x.Course.Title, 52 | Grade = x.Grade.HasValue ? x.Grade.Value.ToString() : "NO GRADE YET" 53 | }); 54 | 55 | return enrollmentModels.ToList(); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Document/0.prnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Document/0.prnx -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/ExportInfo/0.prnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/ExportInfo/0.prnx -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/ExportInfo/1.prnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/ExportInfo/1.prnx -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Metadata/0.prnx: -------------------------------------------------------------------------------- 1 | {"BuilderId":"2f413f66b4ea452c8faeef6fb5d2a019","Finished":false,"StartBuildTimeUtc":"\/Date(1639660581715)\/"} -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Metadata/1.prnx: -------------------------------------------------------------------------------- 1 | {"BuilderId":"2f413f66b4ea452c8faeef6fb5d2a019","Finished":true} -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Metadata/2.prnx: -------------------------------------------------------------------------------- 1 | {"BuilderId":"2f413f66b4ea452c8faeef6fb5d2a019","DocumentDetails":{"canPerformContinuousExport":true,"drillDownKeys":[],"errors":[],"exportOptions":"{\"Html\":{\"@PageBorderColor\":\"Black\",\"@Title\":\"NewReport\",\"@EmbedImagesInHTML\":\"true\"},\"Mht\":{\"@PageBorderColor\":\"Black\",\"@Title\":\"NewReport\"},\"PrintPreview\":{\"@DefaultFileName\":\"NewReport\"},\"MailMessage\":{\"@PageBorderColor\":\"Black\",\"@Title\":\"NewReport\"}}","pageCount":1,"sortingState":[]},"Finished":true} -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Page/0.prnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.Angular/ViewerStorages/Documents/803b2d4fd99079e7b7752d60b30a62b3/Page/0.prnx -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/ViewerStorages/Reports/d3b31846ec8db38d248596e6af17c743/reportDetails.json: -------------------------------------------------------------------------------- 1 | {"isCachedReportSource":true,"reportUrl":"1"} -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "DevExpress": "Debug" 6 | } 7 | }, 8 | "IdentityServer": { 9 | "Key": { 10 | "Type": "Development" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Angular/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultMSSqlConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-AspNetCore.Reporting.Angular-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true", 4 | "DefaultSqliteConnection": "Data Source=Database/application.db" 5 | }, 6 | "Logging": { 7 | "LogLevel": { 8 | "Default": "Warning", 9 | "Microsoft": "Warning", 10 | "Microsoft.Hosting.Lifetime": "Information" 11 | } 12 | }, 13 | "IdentityServer": { 14 | "Clients": { 15 | "AspNetCore.Reporting.Angular": { 16 | "Profile": "IdentityServerSPA" 17 | } 18 | } 19 | }, 20 | "AllowedHosts": "*" 21 | } 22 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/AspNetCore.Reporting.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | Library 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Data/Course.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace AspNetCore.Reporting.Common.Data { 5 | public class Course { 6 | [DatabaseGenerated(DatabaseGeneratedOption.None)] 7 | public int CourseID { get; set; } 8 | public string Title { get; set; } 9 | public int Credits { get; set; } 10 | 11 | public ICollection Enrollments { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Data/Enrollment.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.Common.Data { 2 | public enum Grade { 3 | A, B, C, D, F 4 | } 5 | 6 | public class Enrollment { 7 | public int EnrollmentID { get; set; } 8 | public Grade? Grade { get; set; } 9 | 10 | public Course Course { get; set; } 11 | public StudentIdentity Student { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Data/IReportEntityProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace AspNetCore.Reporting.Common.Data { 4 | public interface IReportEntityProvider { 5 | DbSet Reports { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Data/IStudentEntityProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace AspNetCore.Reporting.Common.Data { 4 | public interface IStudentEntityProvider { 5 | DbSet Students { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Data/ReportEntity.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace AspNetCore.Reporting.Common.Data { 5 | public class ReportEntity { 6 | [Key] 7 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 8 | public int ID { get; set; } 9 | public byte[] ReportLayout { get; set; } 10 | public string DisplayName { get; set; } 11 | public StudentIdentity Student { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Data/StudentIdentity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using Microsoft.AspNetCore.Identity; 5 | 6 | namespace AspNetCore.Reporting.Common.Data { 7 | public class StudentIdentity : IdentityUser { 8 | //public int ID { get; set; } 9 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 10 | public override string Id { get => base.Id; set => base.Id = value; } 11 | public string LastName { get; set; } 12 | public string FirstMidName { get; set; } 13 | public DateTime EnrollmentDate { get; set; } 14 | 15 | public ICollection Enrollments { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/CourseModel.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.Common.Models { 2 | public class CourseModel { 3 | public int CourseID { get; set; } 4 | public string CourseTitle { get; set; } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/EnrollmentDetailsModel.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.Common.Models { 2 | public class EnrollmentDetailsModel { 3 | public int EnrollmentID { get; set; } 4 | public string CourseTitle { get; set; } 5 | public string Grade { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/ExportResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetCore.Reporting.Common.Models { 4 | public class ExportResult { 5 | byte[] documentBytes; 6 | public string FileName { get; set; } 7 | public string ContentType { get; set; } 8 | public string ExportOperationId { get; set; } 9 | public string ContentDisposition { get; set; } 10 | public DateTime TimeStamp { get; private set; } 11 | public ExportResult() { 12 | TimeStamp = DateTime.UtcNow; 13 | } 14 | public void AssignBytes(byte[] data) { 15 | documentBytes = data; 16 | } 17 | public byte[] GetBytes() { 18 | return documentBytes; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/LoginRequest.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace AspNetCore.Reporting.Common.Models { 4 | public class LoginRequest { 5 | [Required] 6 | public string Username { get; set; } 7 | 8 | [Required] 9 | public string UserID { get; set; }//We have created predefined users for simplicity, so we use it instead of hashed password in demo purposes 10 | 11 | [Required] 12 | public string Password { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/LoginResponse.cs: -------------------------------------------------------------------------------- 1 | using AspNetCore.Reporting.Common.Data; 2 | 3 | namespace AspNetCore.Reporting.Common.Models { 4 | public class LoginResponse { 5 | public string Id { get; set; } 6 | public string FirstMidName { get; set; } 7 | public string LastName { get; set; } 8 | public string Token { get; set; } 9 | 10 | public LoginResponse(StudentIdentity student, string token) { 11 | Id = student.Id; 12 | FirstMidName = student.FirstMidName; 13 | LastName = student.LastName; 14 | Token = token; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/LoginScreenModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc.Rendering; 3 | 4 | namespace AspNetCore.Reporting.Common.Models { 5 | public class LoginScreenModel { 6 | public string UserId { get; set; } 7 | public IList Users { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/ReportingControlModel.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.Common.Models { 2 | public class ReportingControlModel { 3 | public string Id { get; set; } 4 | public string Title { get; set; } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Models/StudentDetailsModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetCore.Reporting.Common.Models { 4 | public class StudentDetailsModel { 5 | public string StudentID { get; set; } 6 | public string FirstMidName { get; set; } 7 | public string LastName { get; set; } 8 | public DateTime EnrollmentDate { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/IAuthenticatiedUserService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Security.Claims; 3 | using System.Threading.Tasks; 4 | using AspNetCore.Reporting.Common.Models; 5 | 6 | namespace AspNetCore.Reporting.Common.Services { 7 | public interface IAuthenticatiedUserService { 8 | string GetCurrentUserId(); 9 | string GetCurrentUserName(); 10 | IEnumerable GetCurrentUserClaims(); 11 | Task AuthenticateAsync(LoginRequest loginRequest); 12 | IEnumerable GetStudentList(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/ObjectDataSourceInjector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DevExpress.DataAccess.ObjectBinding; 3 | using DevExpress.XtraReports.Native.Data; 4 | using DevExpress.XtraReports.UI; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace AspNetCore.Reporting.Common.Services { 8 | public interface IObjectDataSourceInjector { 9 | void Process(XtraReport report); 10 | } 11 | 12 | class ObjectDataSourceInjector : IObjectDataSourceInjector { 13 | IServiceProvider ServiceProvider { get; } 14 | 15 | public ObjectDataSourceInjector(IServiceProvider serviceProvider) { 16 | ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); 17 | } 18 | 19 | public void Process(XtraReport report) { 20 | var dse = new UniqueDataSourceEnumerator(); 21 | foreach(var dataSource in dse.EnumerateDataSources(report, true)) { 22 | if(dataSource is ObjectDataSource ods && ods.DataSource is Type dataSourceType) { 23 | ods.DataSource = ServiceProvider.GetRequiredService(dataSourceType); 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/CustomExceptionHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using DevExpress.XtraReports.Web.QueryBuilder.Services; 4 | using DevExpress.XtraReports.Web.ReportDesigner.Services; 5 | using DevExpress.XtraReports.Web.WebDocumentViewer; 6 | 7 | namespace AspNetCore.Reporting.Common.Services.Reporting { 8 | public class CustomWebDocumentViewerExceptionHandler : WebDocumentViewerExceptionHandler { 9 | public override string GetExceptionMessage(Exception ex) { 10 | if(ex is FileNotFoundException) { 11 | #if DEBUG 12 | return ex.Message; 13 | #else 14 | return "File is not found."; 15 | #endif 16 | } 17 | return base.GetExceptionMessage(ex); 18 | } 19 | public override string GetUnknownExceptionMessage(Exception ex) { 20 | return $"{ex.GetType().Name} occurred. See the log file for more details."; 21 | } 22 | } 23 | 24 | public class CustomReportDesignerExceptionHandler : ReportDesignerExceptionHandler { 25 | public override string GetExceptionMessage(Exception ex) { 26 | if(ex is FileNotFoundException) { 27 | #if DEBUG 28 | return ex.Message; 29 | #else 30 | return "File is not found."; 31 | #endif 32 | } 33 | return base.GetExceptionMessage(ex); 34 | } 35 | public override string GetUnknownExceptionMessage(Exception ex) { 36 | return $"{ex.GetType().Name} occurred. See the log file for more details."; 37 | } 38 | } 39 | public class CustomQueryBuilderExceptionHandler : QueryBuilderExceptionHandler { 40 | public override string GetUnknownExceptionMessage(Exception ex) { 41 | return $"{ex.GetType().Name} occurred. See the log file for more details."; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/CustomObjectDataSourceWizardServices.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using DevExpress.DataAccess.Web; 6 | 7 | namespace AspNetCore.Reporting.Common.Services.Reporting { 8 | 9 | public class CustomObjectDataSourceConstructorFilterService : IObjectDataSourceConstructorFilterService { 10 | readonly IObjectDataSourceWizardTypeProvider wizardTypeProvider; 11 | 12 | public CustomObjectDataSourceConstructorFilterService(IObjectDataSourceWizardTypeProvider wizardTypeProvider) { 13 | this.wizardTypeProvider = wizardTypeProvider ?? throw new ArgumentNullException(nameof(wizardTypeProvider)); 14 | } 15 | 16 | public IEnumerable Filter(Type dataSourceType, IEnumerable constructors) { 17 | if(wizardTypeProvider.GetAvailableTypes(null).Contains(dataSourceType)) { 18 | return constructors.Where(x => !x.GetParameters().Any()); 19 | } 20 | 21 | return constructors; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/CustomPreviewReportCustomizationService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using DevExpress.XtraReports.UI; 3 | using DevExpress.XtraReports.Web.ReportDesigner.Services; 4 | 5 | namespace AspNetCore.Reporting.Common.Services.Reporting { 6 | public class CustomPreviewReportCustomizationService : PreviewReportCustomizationService { 7 | readonly IObjectDataSourceInjector objectDataSourceInjector; 8 | public CustomPreviewReportCustomizationService(IObjectDataSourceInjector objectDataSourceInjector) { 9 | this.objectDataSourceInjector = objectDataSourceInjector; 10 | } 11 | public override void CustomizeReport(XtraReport report) { 12 | objectDataSourceInjector.Process(report); 13 | } 14 | public override async Task CustomizeReportAsync(XtraReport report) { 15 | CustomizeReport(report); 16 | await Task.CompletedTask; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/CustomReportProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Design; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using DevExpress.XtraReports.Services; 5 | using DevExpress.XtraReports.UI; 6 | using DevExpress.XtraReports.Web.Extensions; 7 | 8 | namespace AspNetCore.Reporting.Common.Services.Reporting { 9 | public class CustomReportProvider : IReportProvider { 10 | readonly ReportStorageWebExtension reportStorageWebExtension; 11 | readonly IObjectDataSourceInjector dataSourceInjector; 12 | 13 | public CustomReportProvider(ReportStorageWebExtension reportStorageWebExtension, IObjectDataSourceInjector dataSourceInjector) { 14 | this.reportStorageWebExtension = reportStorageWebExtension; 15 | this.dataSourceInjector = dataSourceInjector; 16 | } 17 | public XtraReport GetReport(string id, ReportProviderContext context) { 18 | var reportLayoutBytes = reportStorageWebExtension.GetData(id); 19 | using(var ms = new MemoryStream(reportLayoutBytes)) { 20 | var report = XtraReport.FromXmlStream(ms); 21 | var container = (IServiceContainer)report; 22 | container.AddService(typeof(IReportProvider), this); 23 | dataSourceInjector.Process(report); 24 | return report; 25 | } 26 | } 27 | } 28 | 29 | public class CustomReportProviderAsync : IReportProviderAsync { 30 | readonly ReportStorageWebExtension reportStorageWebExtension; 31 | readonly IObjectDataSourceInjector dataSourceInjector; 32 | 33 | public CustomReportProviderAsync(ReportStorageWebExtension reportStorageWebExtension, IObjectDataSourceInjector dataSourceInjector) { 34 | this.reportStorageWebExtension = reportStorageWebExtension; 35 | this.dataSourceInjector = dataSourceInjector; 36 | } 37 | public async Task GetReportAsync(string id, ReportProviderContext context) { 38 | var reportLayoutBytes = await reportStorageWebExtension.GetDataAsync(id); 39 | using(var ms = new MemoryStream(reportLayoutBytes)) { 40 | var report = XtraReport.FromXmlStream(ms); 41 | var container = (IServiceContainer)report; 42 | container.AddService(typeof(IReportProviderAsync), this); 43 | dataSourceInjector.Process(report); 44 | return report; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/CustomSqlDataConnectionProviderFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DevExpress.Data.Entity; 4 | using DevExpress.DataAccess.ConnectionParameters; 5 | using DevExpress.DataAccess.Native; 6 | using DevExpress.DataAccess.Sql; 7 | using DevExpress.DataAccess.Web; 8 | using DevExpress.DataAccess.Wizard.Services; 9 | using Microsoft.AspNetCore.Http; 10 | using Microsoft.Extensions.Configuration; 11 | 12 | namespace AspNetCore.Reporting.Common.Services.Reporting { 13 | public class CustomSqlDataConnectionProviderFactory : IConnectionProviderFactory { 14 | readonly IConnectionProviderService connectionProviderService; 15 | public CustomSqlDataConnectionProviderFactory(IConnectionProviderService connectionProviderService) { 16 | this.connectionProviderService = connectionProviderService; 17 | } 18 | public IConnectionProviderService Create() { 19 | return connectionProviderService; 20 | } 21 | } 22 | 23 | public class CustomConnectionProviderService : IConnectionProviderService { 24 | readonly IConfiguration configuration; 25 | readonly IHttpContextAccessor httpContextAccessor; 26 | public CustomConnectionProviderService(IConfiguration configuration, IHttpContextAccessor httpContextAccessor) { 27 | this.configuration = configuration; 28 | this.httpContextAccessor = httpContextAccessor; 29 | } 30 | 31 | public SqlDataConnection LoadConnection(string connectionName) { 32 | var connectionStringSection = configuration.GetSection("ReportingDataConnectionStrings"); 33 | var connectionString = connectionStringSection?[connectionName]; 34 | if (string.IsNullOrEmpty(connectionString)) 35 | throw new KeyNotFoundException($"Connection string '{connectionName}' not found."); 36 | var connectionParameters = new CustomStringConnectionParameters(connectionString); 37 | return new SqlDataConnection(connectionName, connectionParameters); 38 | } 39 | 40 | public SqlDataConnection WrongLoadConnection(string connectionName) { 41 | var connectionString = configuration.GetSection("ReportingDataConnectionStrings")?[connectionName]; 42 | if(string.IsNullOrEmpty(connectionString)) 43 | throw new ArgumentException("There is no connection with name: " + connectionName); 44 | return new SqlDataConnection { 45 | Name = connectionName, 46 | ConnectionString = connectionString, 47 | StoreConnectionNameOnly = true, 48 | ConnectionStringSerializable = connectionString, 49 | ProviderKey = "SQLite" 50 | }; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/CustomSqlDataSourceWizardConnectionStringsProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using DevExpress.DataAccess.ConnectionParameters; 4 | using DevExpress.DataAccess.Web; 5 | using Microsoft.Extensions.Configuration; 6 | 7 | namespace AspNetCore.Reporting.Common.Services.Reporting { 8 | public class CustomSqlDataSourceWizardConnectionStringsProvider : IDataSourceWizardConnectionStringsProvider { 9 | IConfiguration Configuration { get; } 10 | public CustomSqlDataSourceWizardConnectionStringsProvider(IConfiguration configuration) { 11 | Configuration = configuration; 12 | } 13 | public Dictionary GetConnectionDescriptions() { 14 | var connections = Configuration.GetSection("ReportingDataConnectionStrings").AsEnumerable(makePathsRelative: true).ToDictionary(x => x.Key, x => x.Key); 15 | return connections; 16 | } 17 | 18 | public DataConnectionParametersBase GetDataConnectionParameters(string name) { 19 | return null;//to prevent serialization of encrypted connection parameters 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/Reporting/ReportingLoggerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DevExpress.XtraReports.Web.ClientControls; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace AspNetCore.Reporting.Common.Services.Reporting { 6 | public class ReportingLoggerService: LoggerService { 7 | readonly ILogger logger; 8 | public ReportingLoggerService(ILogger logger) { 9 | this.logger = logger; 10 | } 11 | public override void Error(Exception exception, string message) { 12 | var logMessage = $"[{DateTime.Now}]: Exception occurred. Message: '{message}'. Exception Details:{Environment.NewLine}{exception}"; 13 | logger.LogError(logMessage); 14 | } 15 | 16 | public override void Info(string message) { 17 | logger.LogInformation(message); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/ScopedDbContextProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace AspNetCore.Reporting.Common.Services { 6 | public interface IScopedDbContextProvider where T : DbContext { 7 | DbContextScope GetDbContextScope(); 8 | } 9 | 10 | // NOTE: This provider isolates the rest of the code from the IServiceProvider. 11 | // That way, we can clearly understand that the consumers of IScopedDbContextProvider requre specific scopes... 12 | public class ScopedDbContextProvider : IScopedDbContextProvider where T : DbContext { 13 | readonly IServiceProvider provider; 14 | 15 | public ScopedDbContextProvider(IServiceProvider provider) { 16 | this.provider = provider ?? throw new ArgumentNullException(nameof(provider)); 17 | } 18 | 19 | public DbContextScope GetDbContextScope() { 20 | var scope = provider.CreateScope(); 21 | return new DbContextScope(scope); 22 | } 23 | } 24 | 25 | public class DbContextScope : IDisposable where T : DbContext { 26 | readonly IServiceScope scope; 27 | public T DbContext { get; private set; } 28 | 29 | public DbContextScope(IServiceScope scope) { 30 | this.scope = scope ?? throw new ArgumentNullException(nameof(scope)); 31 | DbContext = scope.ServiceProvider.GetRequiredService(); 32 | } 33 | 34 | public void Dispose() { 35 | scope.Dispose(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.Common/Services/UserService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using AspNetCore.Reporting.Common.Data; 7 | using AspNetCore.Reporting.Common.Models; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.EntityFrameworkCore; 10 | 11 | namespace AspNetCore.Reporting.Common.Services { 12 | public class UserService : IAuthenticatiedUserService where T : DbContext, IStudentEntityProvider { 13 | readonly IHttpContextAccessor contextAccessor; 14 | readonly T userEntityProvider; 15 | 16 | public UserService(IHttpContextAccessor contextAccessor, T userEntityProvider) { 17 | this.contextAccessor = contextAccessor ?? throw new ArgumentNullException(nameof(contextAccessor)); 18 | this.userEntityProvider = userEntityProvider ?? throw new ArgumentNullException(nameof(userEntityProvider)); 19 | } 20 | 21 | public string GetCurrentUserId() { 22 | var sidStr = contextAccessor.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid); 23 | return sidStr?.Value; 24 | } 25 | 26 | public IEnumerable GetCurrentUserClaims() { 27 | return contextAccessor.HttpContext.User?.Claims ?? Enumerable.Empty(); 28 | } 29 | 30 | public string GetCurrentUserName() { 31 | return contextAccessor.HttpContext.User.Claims.Single(x => x.Type == ClaimTypes.Name).Value; 32 | } 33 | 34 | public async Task AuthenticateAsync(LoginRequest loginRequest) { 35 | var student = await userEntityProvider.Students.FirstOrDefaultAsync(x => x.Id == loginRequest.UserID); 36 | if(student == null) 37 | return null; 38 | return GetStudentModel(student); 39 | } 40 | 41 | public IEnumerable GetStudentList() { 42 | return userEntityProvider.Students.Select(GetStudentModel); 43 | } 44 | 45 | StudentDetailsModel GetStudentModel(StudentIdentity student) { 46 | return new StudentDetailsModel { 47 | StudentID = student.Id, 48 | FirstMidName = student.FirstMidName, 49 | LastName = student.LastName, 50 | EnrollmentDate = student.EnrollmentDate 51 | }; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## DevExpress 3 | ################# 4 | 5 | ## Examples Web root 6 | **/wwwroot/**/*.bundle.css 7 | **/wwwroot/**/dx-reporting-skeleton-screen.css 8 | **/wwwroot/**/*.bundle.js 9 | **/wwwroot/**/dxicons.ttf 10 | **/wwwroot/**/dxicons.woff 11 | **/wwwroot/**/dxicons.woff2 12 | **/wwwroot/**/dxiconsmaterial.ttf 13 | **/wwwroot/**/dxiconsmaterial.woff 14 | **/wwwroot/**/dxiconsmaterial.woff2 15 | **/wwwroot/lib/jquery/**/* 16 | **/wwwroot/lib/jquery/* 17 | **/ViewerStorages/ -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/AspNetCore.Reporting.MVC.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | aspnet-AspNetCore.Reporting.MVC-4D4509A9-62A2-4451-8E5B-B8895C984457 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/AspNetCore.Reporting.MVC.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30503.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Reporting.MVC", "AspNetCore.Reporting.MVC.csproj", "{1255BCA4-CB7A-4317-9C9E-5F505213341B}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Reporting.Common", "..\AspNetCore.Reporting.Common\AspNetCore.Reporting.Common.csproj", "{669F289E-F10D-4239-A847-EA67CD0C70FB}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1255BCA4-CB7A-4317-9C9E-5F505213341B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {1255BCA4-CB7A-4317-9C9E-5F505213341B}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {1255BCA4-CB7A-4317-9C9E-5F505213341B}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {1255BCA4-CB7A-4317-9C9E-5F505213341B}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {669F289E-F10D-4239-A847-EA67CD0C70FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {669F289E-F10D-4239-A847-EA67CD0C70FB}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {669F289E-F10D-4239-A847-EA67CD0C70FB}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {669F289E-F10D-4239-A847-EA67CD0C70FB}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {29B055C0-93AB-4D0B-81BA-F8B9718F6BFE} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Security; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using AspNetCore.Reporting.Common.Data; 7 | using AspNetCore.Reporting.MVC.Controllers; 8 | using AspNetCore.Reporting.MVC.Data; 9 | using AspNetCore.Reporting.MVC.Models; 10 | using Microsoft.AspNetCore.Authentication; 11 | using Microsoft.AspNetCore.Authentication.Cookies; 12 | using Microsoft.AspNetCore.Mvc; 13 | using Microsoft.AspNetCore.Mvc.Rendering; 14 | using Microsoft.EntityFrameworkCore; 15 | 16 | namespace ConnectionProviderSample.Controllers { 17 | public class AccountController : Controller { 18 | 19 | [HttpGet] 20 | public async Task Login([FromServices] SchoolDbContext dbContext) { 21 | return View(await GetLoginScreenModelAsync(dbContext)); 22 | } 23 | 24 | [HttpPost] 25 | [ValidateAntiForgeryToken] 26 | public async Task Login([FromServices] SchoolDbContext dbContext, string userId, string returnUrl) { 27 | var user = await dbContext.Users.FindAsync(userId); 28 | if(user != null) { 29 | await SignIn(user); 30 | 31 | if(Url.IsLocalUrl(returnUrl)) { 32 | return Redirect(returnUrl); 33 | } 34 | return RedirectToAction(nameof(HomeController.Index), "Home"); 35 | } 36 | 37 | throw new SecurityException($"User not found by the ID: {userId}"); 38 | } 39 | 40 | [HttpPost] 41 | public async Task Logout() { 42 | await HttpContext.SignOutAsync(); 43 | return RedirectToAction(nameof(Login)); 44 | } 45 | 46 | async Task SignIn(StudentIdentity user) { 47 | string userName = $"{user.FirstMidName} {user.LastName}"; 48 | 49 | var claims = new List { 50 | new Claim(ClaimTypes.Name, userName), 51 | new Claim(ClaimTypes.NameIdentifier, userName), 52 | new Claim(ClaimTypes.Sid, user.Id) 53 | }; 54 | 55 | var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); 56 | identity.AddClaims(claims); 57 | 58 | var principal = new ClaimsPrincipal(identity); 59 | await HttpContext.SignInAsync(principal, new AuthenticationProperties { IsPersistent = true }); 60 | } 61 | 62 | async Task GetLoginScreenModelAsync(SchoolDbContext dBContext) { 63 | var model = new LoginScreenModel(); 64 | model.Users = await dBContext.Users 65 | .Select(x => new SelectListItem { 66 | Value = x.Id, 67 | Text = $"{x.FirstMidName} {x.LastName}" 68 | }) 69 | .ToListAsync(); 70 | return model; 71 | } 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Controllers/CustomMVCReportingControllers.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using DevExpress.AspNetCore.Reporting.QueryBuilder; 3 | using DevExpress.AspNetCore.Reporting.QueryBuilder.Native.Services; 4 | using DevExpress.AspNetCore.Reporting.ReportDesigner; 5 | using DevExpress.AspNetCore.Reporting.ReportDesigner.Native.Services; 6 | using DevExpress.AspNetCore.Reporting.WebDocumentViewer; 7 | using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services; 8 | using Microsoft.AspNetCore.Authorization; 9 | using Microsoft.AspNetCore.Mvc; 10 | 11 | namespace AspNetCore.Reporting.Common.Controllers { 12 | [Authorize] 13 | [Route("DXXRDVMVC")] 14 | [AutoValidateAntiforgeryToken] 15 | public class CustomMVCWebDocumentViewerController : WebDocumentViewerController { 16 | public CustomMVCWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) { 17 | } 18 | 19 | public override Task Invoke() { 20 | return base.Invoke(); 21 | } 22 | } 23 | 24 | [Authorize] 25 | [Route("DXXQBMVC")] 26 | [AutoValidateAntiforgeryToken] 27 | public class CustomMVCQueryBuilderController : QueryBuilderController { 28 | public CustomMVCQueryBuilderController(IQueryBuilderMvcControllerService controllerService) : base(controllerService) { 29 | } 30 | public override Task Invoke() { 31 | return base.Invoke(); 32 | } 33 | } 34 | 35 | 36 | [Authorize] 37 | [Route("DXXRDMVC")] 38 | [AutoValidateAntiforgeryToken] 39 | public class CustomMVCReportDesignerController : ReportDesignerController { 40 | public CustomMVCReportDesignerController(IReportDesignerMvcControllerService controllerService) : base(controllerService) { 41 | } 42 | 43 | public override Task Invoke() { 44 | return base.Invoke(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Data/DbInitializer.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using AspNetCore.Reporting.Common.Data; 4 | using AspNetCore.Reporting.Common.Reports; 5 | using DevExpress.XtraReports.UI; 6 | 7 | namespace AspNetCore.Reporting.MVC.Data { 8 | public static class DbInitializer { 9 | public static void Initialize(SchoolDbContext context, ReportsFactory factory) { 10 | context.Database.EnsureDeleted(); 11 | context.Database.EnsureCreated(); 12 | // Look for any students. 13 | if(context.Students.Any()) { 14 | return;// DB has been seeded 15 | } 16 | 17 | var students = DbDefaultsGenerator.GenerateStudents(null); 18 | foreach(StudentIdentity s in students) { 19 | context.Students.Add(s); 20 | foreach(var report in factory.Reports.Select(a => new { a.Key, Value = a.Value() })) { 21 | context.Reports.Add(new ReportEntity() { 22 | DisplayName = string.IsNullOrEmpty(report.Value.DisplayName) ? report.Key : report.Value.DisplayName, 23 | ReportLayout = ReportToByteArray(report.Value), 24 | Student = s 25 | }); 26 | } 27 | } 28 | context.SaveChanges(); 29 | var courses = DbDefaultsGenerator.GetCourses(); 30 | foreach(Course c in courses) { 31 | context.Courses.Add(c); 32 | } 33 | context.SaveChanges(); 34 | 35 | var enrollments = DbDefaultsGenerator.GetEnrollments(students, courses); 36 | foreach(Enrollment e in enrollments) { 37 | context.Enrollments.Add(e); 38 | } 39 | context.SaveChanges(); 40 | } 41 | 42 | static byte[] ReportToByteArray(XtraReport report) { 43 | using(var memoryStream = new MemoryStream()) { 44 | report.SaveLayoutToXml(memoryStream); 45 | return memoryStream.ToArray(); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Data/SchoolDbContext.cs: -------------------------------------------------------------------------------- 1 | using AspNetCore.Reporting.Common.Data; 2 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace AspNetCore.Reporting.MVC.Data { 6 | public class SchoolDbContext : IdentityDbContext, IStudentEntityProvider, IReportEntityProvider { 7 | public SchoolDbContext(DbContextOptions options) : base(options) { 8 | } 9 | 10 | public DbSet Courses { get; set; } 11 | public DbSet Enrollments { get; set; } 12 | public DbSet Students { get; set; } 13 | public DbSet Reports { get; set; } 14 | 15 | protected override void OnModelCreating(ModelBuilder modelBuilder) { 16 | base.OnModelCreating(modelBuilder); 17 | modelBuilder.Entity().ToTable("Courses"); 18 | modelBuilder.Entity().ToTable("Enrollments"); 19 | modelBuilder.Entity().ToTable("Students"); 20 | modelBuilder.Entity().ToTable("Reports"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Database/application.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/Database/application.db -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Database/application.db-shm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/Database/application.db-shm -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Database/application.db-wal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/Database/application.db-wal -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Database/nwind.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/Database/nwind.db -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Database/nwind.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/Database/nwind.json -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/CourseModel.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.MVC.Models { 2 | public class CourseModel { 3 | public int CourseID { get; set; } 4 | public string CourseTitle { get; set; } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/CustomDesignerModel.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.XtraReports.Web.ReportDesigner; 2 | 3 | namespace AspNetCore.Reporting.MVC.Models { 4 | public class CustomDesignerModel { 5 | public ReportDesignerModel DesignerModel { get; set; } 6 | public string Title{ get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/CustomViewerModel.cs: -------------------------------------------------------------------------------- 1 | using DevExpress.XtraReports.Web.WebDocumentViewer; 2 | 3 | namespace AspNetCore.Reporting.MVC.Models { 4 | public class CustomViewerModel { 5 | public WebDocumentViewerModel ViewerModel { get; set; } 6 | public string Title { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/EnrollmentDetailsModel.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.MVC.Models { 2 | public class EnrollmentDetailsModel { 3 | public int EnrollmentID { get; set; } 4 | public string CourseTitle { get; set; } 5 | public string Grade { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetCore.Reporting.MVC.Models { 4 | public class ErrorViewModel { 5 | public string RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/ExportResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetCore.Reporting.MVC.Models { 4 | public class ExportResult { 5 | byte[] documentBytes; 6 | public string FileName { get; set; } 7 | public string ContentType { get; set; } 8 | public string ExportOperationId { get; set; } 9 | public string ContentDisposition { get; set; } 10 | public DateTime TimeStamp { get; private set; } 11 | public ExportResult() { 12 | TimeStamp = DateTime.UtcNow; 13 | } 14 | public void AssignBytes(byte[] data) { 15 | documentBytes = data; 16 | } 17 | public byte[] GetBytes() { 18 | return documentBytes; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/LoginRequest.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace AspNetCore.Reporting.MVC.Models { 4 | public class LoginRequest { 5 | [Required] 6 | public string Username { get; set; } 7 | 8 | [Required] 9 | public string UserID { get; set; }//We have created predefined users for simplicity, so we use it instead of hashed password in demo purposes 10 | 11 | [Required] 12 | public string Password { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/LoginResponse.cs: -------------------------------------------------------------------------------- 1 | using AspNetCore.Reporting.Common.Data; 2 | using AspNetCore.Reporting.MVC.Data; 3 | 4 | namespace AspNetCore.Reporting.MVC.Models { 5 | public class LoginResponse { 6 | public string Id { get; set; } 7 | public string FirstMidName { get; set; } 8 | public string LastName { get; set; } 9 | public string Token { get; set; } 10 | 11 | public LoginResponse(StudentIdentity student, string token) { 12 | Id = student.Id; 13 | FirstMidName = student.FirstMidName; 14 | LastName = student.LastName; 15 | Token = token; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/LoginScreenModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc.Rendering; 3 | 4 | namespace AspNetCore.Reporting.MVC.Models { 5 | public class LoginScreenModel { 6 | public string UserId { get; set; } 7 | public IList Users { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/ReportingControlModel.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetCore.Reporting.MVC.Models { 2 | public class ReportingControlModel { 3 | public string Id { get; set; } 4 | public string Title { get; set; } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Models/StudentDetailsModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetCore.Reporting.MVC.Models { 4 | public class StudentDetailsModel { 5 | public string StudentID { get; set; } 6 | public string FirstMidName { get; set; } 7 | public string LastName { get; set; } 8 | public DateTime EnrollmentDate { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Program.cs: -------------------------------------------------------------------------------- 1 | using AspNetCore.Reporting.MVC.Data; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | 6 | namespace AspNetCore.Reporting.MVC { 7 | public class Program { 8 | public static void Main(string[] args) { 9 | var host = CreateHostBuilder(args).Build(); 10 | InitializeDb(host); 11 | host.Run(); 12 | } 13 | 14 | static void InitializeDb(IHost host) { 15 | using(var scope = host.Services.CreateScope()) { 16 | var dbContext = scope.ServiceProvider.GetRequiredService(); 17 | DbInitializer.Initialize(dbContext, new Common.Reports.ReportsFactory()); 18 | } 19 | } 20 | 21 | public static IHostBuilder CreateHostBuilder(string[] args) => 22 | Host.CreateDefaultBuilder(args) 23 | .ConfigureWebHostDefaults(webBuilder => { 24 | webBuilder.UseStartup(); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:51396", 7 | "sslPort": 44385 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "AspNetCore.Reporting.MVC": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "mssql1": { 4 | "type": "mssql", 5 | "connectionId": "DefaultConnection" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "mssql1": { 4 | "type": "mssql.local", 5 | "connectionId": "DefaultConnection" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Reports/CourseListReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using DevExpress.XtraReports.UI; 6 | 7 | namespace AspNetCore.Reporting.MVC.Reports { 8 | public partial class CourseListReport : DevExpress.XtraReports.UI.XtraReport { 9 | public CourseListReport() { 10 | InitializeComponent(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Reports/MyEnrollmentsReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using DevExpress.XtraReports.UI; 6 | 7 | namespace AspNetCore.Reporting.MVC.Reports { 8 | public partial class MyEnrollmentsReport : DevExpress.XtraReports.UI.XtraReport { 9 | public MyEnrollmentsReport() { 10 | InitializeComponent(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Reports/ReportsFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DevExpress.XtraReports.UI; 4 | 5 | namespace AspNetCore.Reporting.Common.Reports { 6 | public class ReportsFactory { 7 | public Dictionary> Reports { 8 | get { 9 | return new Dictionary>() { 10 | ["Enrollments"] = () => new MVC.Reports.MyEnrollmentsReport(), 11 | ["CourseList"] = () => new MVC.Reports.CourseListReport(), 12 | }; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Services/CourseListReportRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AspNetCore.Reporting.MVC.Data; 5 | using AspNetCore.Reporting.Common.Models; 6 | 7 | namespace AspNetCore.Reporting.Common.Services { 8 | public class CourseListReportRepository { 9 | readonly IScopedDbContextProvider scopedDbContextProvider; 10 | 11 | public CourseListReportRepository() { 12 | // We use this parameterless constructor in the Data Source Wizard only, and not for the actual instantiation of the repository object. 13 | throw new NotSupportedException(); 14 | } 15 | 16 | public CourseListReportRepository(IScopedDbContextProvider scopedDbContextProvider) { 17 | this.scopedDbContextProvider = scopedDbContextProvider ?? throw new ArgumentNullException(nameof(scopedDbContextProvider)); 18 | } 19 | 20 | public IList GetCourses() { 21 | using(var dbContextScope = scopedDbContextProvider.GetDbContextScope()) { 22 | var dbContext = dbContextScope.DbContext; 23 | var model = dbContext.Courses.Select(x => 24 | new CourseModel { 25 | CourseID = x.CourseID, 26 | CourseTitle = x.Title 27 | }) 28 | .ToList(); 29 | return model; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Services/CustomObjectDataSourceWizardTypeProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DevExpress.DataAccess.Web; 4 | 5 | namespace AspNetCore.Reporting.Common.Services.Reporting { 6 | public class CustomObjectDataSourceWizardTypeProvider : IObjectDataSourceWizardTypeProvider { 7 | public IEnumerable GetAvailableTypes(string context) { 8 | return new[] { 9 | typeof(CourseListReportRepository), 10 | typeof(MyEnrollmentsReportRepository) 11 | }; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Services/MyEnrollmentsReportRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AspNetCore.Reporting.MVC.Data; 5 | using AspNetCore.Reporting.Common.Models; 6 | 7 | namespace AspNetCore.Reporting.Common.Services { 8 | public class MyEnrollmentsReportRepository { 9 | readonly string studentId; 10 | readonly IScopedDbContextProvider scopedDbContextProvider; 11 | 12 | public MyEnrollmentsReportRepository() { 13 | // We use this parameterless constructor in the Data Source Wizard only, and not for the actual instantiation of the repository object. 14 | throw new NotSupportedException(); 15 | } 16 | 17 | public MyEnrollmentsReportRepository(IScopedDbContextProvider scopedDbContextProvider, IAuthenticatiedUserService userService) { 18 | this.scopedDbContextProvider = scopedDbContextProvider ?? throw new ArgumentNullException(nameof(scopedDbContextProvider)); 19 | 20 | // NOTE: the repository ctor is invoked in the context of http request. At this point of execution we have access to context-dependent data, like currentUserId. 21 | // The repository MUST read and store all the required context-dependent values for later use. E.g. notice that we do not store the IUserService (which is context/scope dependent), but read the value of current user and store it. 22 | studentId = userService.GetCurrentUserId(); 23 | } 24 | 25 | public StudentDetailsModel GetStudentDetails() { 26 | using(var dbContextScope = scopedDbContextProvider.GetDbContextScope()) { 27 | var dbContext = dbContextScope.DbContext; 28 | var student = dbContext.Students.Find(studentId); 29 | 30 | var model = new StudentDetailsModel { 31 | StudentID = student.Id, 32 | FirstMidName = student.FirstMidName, 33 | LastName = student.LastName, 34 | EnrollmentDate = student.EnrollmentDate 35 | }; 36 | return model; 37 | } 38 | } 39 | 40 | public IList GetEnrollments() { 41 | using(var dbContextScope = scopedDbContextProvider.GetDbContextScope()) { 42 | var dbContext = dbContextScope.DbContext; 43 | var student = dbContext.Students.Find(studentId); 44 | 45 | dbContext.Entry(student).Collection(x => x.Enrollments).Load(); 46 | student.Enrollments.ToList().ForEach(x => dbContext.Entry(x).Reference(c => c.Course).Load()); 47 | 48 | var enrollmentModels = student.Enrollments.Select(x => 49 | new EnrollmentDetailsModel { 50 | EnrollmentID = x.EnrollmentID, 51 | CourseTitle = x.Course.Title, 52 | Grade = x.Grade.HasValue ? x.Grade.Value.ToString() : "NO GRADE YET" 53 | }); 54 | 55 | return enrollmentModels.ToList(); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetCore.Reporting.MVC.Models.LoginScreenModel 2 | 3 | @{ 4 | ViewData["Title"] = "Select account"; 5 | } 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 | LOGIN 14 |
15 |
16 | 17 |
18 | 19 |
20 | 23 |
24 |
25 |
26 |
27 |
-------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Home/DesignReport.cshtml: -------------------------------------------------------------------------------- 1 | @using DevExpress.AspNetCore 2 | @using DevExpress.XtraReports.UI 3 | 4 | @model AspNetCore.Reporting.MVC.Models.CustomDesignerModel 5 | @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf 6 | @functions { 7 | public string GetAntiXsrfRequestToken() { 8 | return Xsrf.GetAndStoreTokens(this.Context).RequestToken; 9 | } 10 | } 11 | 35 | 36 | @{ 37 | ViewData["Title"] = Model.Title; 38 | var designerRender = Html.DevExpress().ReportDesigner("ReportDesigner") 39 | .Height("100%") 40 | .ClientSideModelSettings(clientSide => { 41 | clientSide.IncludeLocalization = false; 42 | clientSide.IncludeCldrData = false; 43 | clientSide.IncludeCldrSupplemental = false; 44 | }) 45 | .ClientSideEvents(events => { 46 | events 47 | .CustomizeLocalization("CustomizeLocalization") 48 | .BeforeRender("DesignerBeforeRender") 49 | .ExitDesigner("Exit"); 50 | }); 51 | 52 | designerRender.Bind(Model.DesignerModel); 53 | 54 | @:@designerRender.RenderHtml() 55 | 56 | } 57 | 58 | @section Scripts { 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | @designerRender.RenderScripts() 68 | } 69 | 70 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Home/DisplayReport.cshtml: -------------------------------------------------------------------------------- 1 | @using DevExpress.AspNetCore 2 | 3 | @model AspNetCore.Reporting.MVC.Models.CustomViewerModel 4 | @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf 5 | @functions { 6 | public string GetAntiXsrfRequestToken() { 7 | return Xsrf.GetAndStoreTokens(this.Context).RequestToken; 8 | } 9 | } 10 | 25 | 26 | @{ 27 | ViewData["Title"] = Model.Title; 28 | var viewerRender = Html.DevExpress().WebDocumentViewer("DocumentViewer") 29 | .ClientSideEvents(x => { 30 | x.CustomizeLocalization("CustomizeLocalization"); 31 | x.BeforeRender("WebDocumentViewer_BeforeRender"); 32 | }) 33 | .ClientSideModelSettings(clientSide => { 34 | clientSide.IncludeLocalization = false; 35 | clientSide.IncludeCldrData = false; 36 | clientSide.IncludeCldrSupplemental = false; 37 | }) 38 | .Height("100%") 39 | .Bind(Model.ViewerModel); 40 | @:@viewerRender.RenderHtml() 41 | 42 | } 43 | 44 | @section Scripts { 45 | 46 | 47 | 48 | 49 | 50 | @viewerRender.RenderScripts() 51 | } 52 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewData["Title"] = "Reporting"; 5 | } 6 | 7 | 8 |
9 |
10 |

Reporting

11 | 14 |
15 |
    16 | @foreach(var item in Model) { 17 |
  • 18 | @item.Title 19 |
    20 |
    21 | 24 | 27 | 30 | 31 |
    32 |
    33 |
  • 34 | } 35 |
36 |
37 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - AspNetCore.Reporting.MVC 7 | 8 | 9 | 10 | 11 |
12 |
13 | 36 |
37 |
38 |
39 | @RenderBody() 40 |
41 |
42 | 43 |
44 |
45 | © 2021 - AspNetCore.Reporting.MVC - Privacy 46 |
47 |
48 |
49 | 50 | 51 | @RenderSection("Scripts", required: false) 52 | 53 | 54 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @inject SignInManager SignInManager 3 | @inject UserManager UserManager 4 | 5 | 27 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AspNetCore.Reporting.Common 2 | @using AspNetCore.Reporting.Common.Data 3 | @using AspNetCore.Reporting.Common.Models 4 | @using AspNetCore.Reporting.MVC 5 | @using AspNetCore.Reporting.MVC.Models 6 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "DevExpress": "Debug" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Data Source=Database/application.db" 4 | }, 5 | "ReportingDataConnectionStrings": { 6 | "NWindConnectionString": "XpoProvider=SQLite;Data Source=Database/nwind.db" 7 | }, 8 | "Logging": { 9 | "LogLevel": { 10 | "Default": "Information", 11 | "Microsoft": "Warning", 12 | "Microsoft.Hosting.Lifetime": "Information" 13 | } 14 | }, 15 | "AllowedHosts": "*" 16 | } 17 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/libman.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "defaultProvider": "filesystem", 4 | "libraries": [ 5 | { 6 | "library": "node_modules/ace-builds/css/", 7 | "destination": "wwwroot/css/ace", 8 | "files": [ "*.png", "*.svg" ] 9 | }, 10 | { 11 | "library": "node_modules/devextreme-dist/css/icons/", 12 | "destination": "wwwroot/css/icons", 13 | "files": [ 14 | "dxicons.ttf", 15 | "dxicons.woff2", 16 | "dxicons.woff", 17 | "dxiconsmaterial.ttf", 18 | "dxiconsmaterial.woff", 19 | "dxiconsmaterial.woff2" 20 | ] 21 | }, 22 | { 23 | "library": "node_modules/devextreme-dist/js/localization/", 24 | "destination": "wwwroot/localization/devextreme", 25 | "files": [ 26 | "de.json" 27 | ] 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aspnetcorereportingmvc", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "@devexpress/analytics-core": "~24.2.1-alpha", 8 | "bootstrap": "^4.3.1", 9 | "devexpress-reporting": "~24.2.1-alpha", 10 | "devextreme-dist": "~24.2.1-alpha" 11 | } 12 | } -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/ambiance-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/ambiance-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/ambiance-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/ambiance-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/ambiance-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/ambiance-3.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/chrome-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/chrome-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/chrome-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/chrome-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_day-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_day-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_day-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_day-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night_low_color-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night_low_color-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night_low_color-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cloud9_night_low_color-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds_midnight-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds_midnight-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds_midnight-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/clouds_midnight-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cobalt-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cobalt-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/cobalt-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/cobalt-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/crimson_editor-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/crimson_editor-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/crimson_editor-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/crimson_editor-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/dawn-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/dawn-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/dawn-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/dawn-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/dracula-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/dracula-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/dracula-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/dracula-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/dreamweaver-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/dreamweaver-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/dreamweaver-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/dreamweaver-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/eclipse-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/eclipse-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/eclipse-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/eclipse-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/github-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/github-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/github-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/github-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/github_dark-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/github_dark-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/github_dark-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/github_dark-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/github_light_default-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/github_light_default-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/github_light_default-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/github_light_default-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gob-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gob-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gob-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gob-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox_dark_hard-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox_dark_hard-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox_light_hard-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox_light_hard-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox_light_hard-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/gruvbox_light_hard-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/idle_fingers-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/idle_fingers-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/idle_fingers-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/idle_fingers-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/iplastic-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/iplastic-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/iplastic-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/iplastic-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/iplastic-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/iplastic-3.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/katzenmilch-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/katzenmilch-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/katzenmilch-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/katzenmilch-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/kr_theme-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/kr_theme-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/kr_theme-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/kr_theme-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/kuroir-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/kuroir-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/kuroir-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/kuroir-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-10.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-10.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-11.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-11.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-12.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-12.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-13.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-14.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-15.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-16.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-17.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-18.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-19.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-20.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-21.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-22.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-22.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-23.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-24.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-25.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-26.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-3.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-4.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-5.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-6.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-6.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-7.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-7.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-8.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-8.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/main-9.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/main-9.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore_soft-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore_soft-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore_soft-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/merbivore_soft-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/mono_industrial-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/mono_industrial-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/mono_industrial-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/mono_industrial-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/monokai-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/monokai-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/monokai-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/monokai-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/one_dark-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/one_dark-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/one_dark-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/one_dark-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/pastel_on_dark-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/pastel_on_dark-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/pastel_on_dark-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/pastel_on_dark-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_dark-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_dark-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_dark-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_dark-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_light-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_light-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_light-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/solarized_light-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/sqlserver-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/sqlserver-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/sqlserver-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/sqlserver-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/terminal-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/terminal-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/terminal-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/terminal-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/textmate-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/textmate-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/textmate-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/textmate-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_blue-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_blue-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_blue-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_blue-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_bright-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_bright-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_bright-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_bright-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_eighties-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_eighties-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_eighties-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/tomorrow_night_eighties-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/twilight-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/twilight-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/twilight-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/twilight-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/vibrant_ink-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/vibrant_ink-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/vibrant_ink-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/vibrant_ink-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/xcode-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/xcode-1.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/ace/xcode-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/AspNetCore.Reporting.MVC/wwwroot/css/ace/xcode-2.png -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | /* Provide sufficient contrast against white background */ 11 | a { 12 | color: #0366d6; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 22 | color: #fff; 23 | background-color: #1b6ec2; 24 | border-color: #1861ac; 25 | } 26 | 27 | /* Sticky footer styles 28 | -------------------------------------------------- */ 29 | html { 30 | font-size: 14px; 31 | } 32 | @media (min-width: 768px) { 33 | html { 34 | font-size: 16px; 35 | } 36 | } 37 | 38 | .border-top { 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | .border-bottom { 42 | border-bottom: 1px solid #e5e5e5; 43 | } 44 | 45 | .box-shadow { 46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 47 | } 48 | 49 | button.accept-policy { 50 | font-size: 1rem; 51 | line-height: inherit; 52 | } 53 | 54 | /* Sticky footer styles 55 | -------------------------------------------------- */ 56 | html { 57 | position: relative; 58 | min-height: 100%; 59 | } 60 | 61 | body { 62 | /* Margin bottom by footer height */ 63 | margin-bottom: 60px; 64 | } 65 | .footer { 66 | position: absolute; 67 | bottom: 0; 68 | width: 100%; 69 | white-space: nowrap; 70 | line-height: 60px; /* Vertically center the text there */ 71 | } 72 | 73 | .container-fluid { 74 | height: 100%; 75 | } 76 | 77 | .container-fluid main { 78 | height: 100%; 79 | } 80 | 81 | .trash { 82 | color: rgb(209, 91, 71); 83 | } 84 | 85 | .flag { 86 | color: rgb(248, 148, 6); 87 | } 88 | 89 | .panel-body { 90 | padding: 0px; 91 | } 92 | 93 | .panel-footer .pagination { 94 | margin: 0; 95 | } 96 | 97 | .panel .glyphicon, .list-group-item .glyphicon { 98 | margin-right: 5px; 99 | } 100 | 101 | .panel-body .radio, .checkbox { 102 | display: inline-block; 103 | margin: 0px; 104 | } 105 | 106 | .panel-body input[type=checkbox]:checked + label { 107 | text-decoration: line-through; 108 | color: rgb(128, 144, 160); 109 | } 110 | 111 | .list-group-item:hover, a.list-group-item:focus { 112 | text-decoration: none; 113 | background-color: rgb(245, 245, 245); 114 | } 115 | 116 | .list-group { 117 | margin-bottom: 0px; 118 | } 119 | -------------------------------------------------------------------------------- /AspNetCore.Reporting.MVC/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | function SetupJwt(bearerToken, xsrf) { 2 | DevExpress.Analytics.Utils.fetchSetup.fetchSettings = { 3 | headers: { 4 | //'Authorization': 'Bearer ' + bearerToken, 5 | 'RequestVerificationToken': xsrf 6 | } 7 | }; 8 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @DevExpressExampleBot -------------------------------------------------------------------------------- /Images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/Images/screenshot.png -------------------------------------------------------------------------------- /Images/skeleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/AspNetCore.Reporting.BestPractices/b99dfe131c17f6d5d7e315167ba19b4d84b95916/Images/skeleton.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This code example is provided "as is" without warranty of any kind. Developer Express Inc ("DevExpress") disclaims all warranties, 2 | either express or implied, including the warranties of merchantability and fitness for a particular purpose. 3 | 4 | For licensing terms and conditions of DevExpress product(s) required for, or associated with the use of this code example, 5 | please refer to the applicable End-User License Agreement at https://www.devexpress.com/Support/licensingfaq.xml -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "runOnWeb": false, 3 | "autoGenerateVb": false 4 | } --------------------------------------------------------------------------------