Base solution for your next web application

Activities of "dev1_premierpoint"

Adding the debugger statement did work yes. Although, I'm still not sure why the regular debug breakpoint won't catch there.

The page is Angular.

I'm expecting a break at the createOdeCred method, so that I can follow the path down the show method within. It is my assumption that the generated createOdeCred method works similarly to the createUser method in that it is called when the create new user (or in the case new odeCred) button is pressed.

import { Component, Injector, ViewEncapsulation, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { OdeCredsServiceProxy, OdeCredDto  } from '@shared/service-proxies/service-proxies';
import { NotifyService } from 'abp-ng2-module';
import { AppComponentBase } from '@shared/common/app-component-base';
import { TokenAuthServiceProxy } from '@shared/service-proxies/service-proxies';
import { CreateOrEditOdeCredModalComponent } from './create-or-edit-odeCred-modal.component';
import { ViewOdeCredModalComponent } from './view-odeCred-modal.component';
import { appModuleAnimation } from '@shared/animations/routerTransition';
import { Table } from 'primeng/table';
import { Paginator } from 'primeng/paginator';
import { LazyLoadEvent } from 'primeng/public_api';
import { FileDownloadService } from '@shared/utils/file-download.service';
import * as _ from 'lodash';
import * as moment from 'moment';

@Component({
    templateUrl: './odeCreds.component.html',
    encapsulation: ViewEncapsulation.None,
    animations: [appModuleAnimation()]
})
export class OdeCredsComponent extends AppComponentBase {

    @ViewChild('createOrEditOdeCredModal', { static: true }) createOrEditOdeCredModal: CreateOrEditOdeCredModalComponent;
    @ViewChild('viewOdeCredModalComponent', { static: true }) viewOdeCredModal: ViewOdeCredModalComponent;
    @ViewChild('dataTable', { static: true }) dataTable: Table;
    @ViewChild('paginator', { static: true }) paginator: Paginator;

    advancedFiltersAreShown = false;
    filterText = '';




    constructor(
        injector: Injector,
        private _odeCredsServiceProxy: OdeCredsServiceProxy,
        private _notifyService: NotifyService,
        private _tokenAuth: TokenAuthServiceProxy,
        private _activatedRoute: ActivatedRoute,
        private _fileDownloadService: FileDownloadService
    ) {
        super(injector);
    }

    getOdeCreds(event?: LazyLoadEvent) {
        if (this.primengTableHelper.shouldResetPaging(event)) {
            this.paginator.changePage(0);
            return;
        }

        this.primengTableHelper.showLoadingIndicator();

        this._odeCredsServiceProxy.getAll(
            this.filterText,
            this.primengTableHelper.getSorting(this.dataTable),
            this.primengTableHelper.getSkipCount(this.paginator, event),
            this.primengTableHelper.getMaxResultCount(this.paginator, event)
        ).subscribe(result => {
            this.primengTableHelper.totalRecordsCount = result.totalCount;
            this.primengTableHelper.records = result.items;
            this.primengTableHelper.hideLoadingIndicator();
        });
    }

    reloadPage(): void {
        this.paginator.changePage(this.paginator.getPage());
    }

    // ###### expecting break here ######
    createOdeCred(): void {
        this.createOrEditOdeCredModal.show();
    }

    deleteOdeCred(odeCred: OdeCredDto): void {
        this.message.confirm(
            '',
            this.l('AreYouSure'),
            (isConfirmed) => {
                if (isConfirmed) {
                    this._odeCredsServiceProxy.delete(odeCred.id)
                        .subscribe(() => {
                            this.reloadPage();
                            this.notify.success(this.l('SuccessfullyDeleted'));
                        });
                }
            }
        );
    }
}

Your documentation says to use "ng build --prod":

https://docs.aspnetzero.com/en/aspnet-core-angular/latest/Deployment-Angular-Publish-IIS#angular-application-publishing

Can I assume that is a bug in the documentation?

I removed the web.config file from the API project and then tested debugging locally. It works fine without the web.config.

Then I used Visual Studio Publish to publish the API project to the IIS server. As expected, VS Publish created the needed web.config file on the fly and deployed it along with everything else to the IIS server.

The web.config file it generates is simple and doesn't include anything related to the environment, which is how it should be. Here is the web.config it generated:

With that web.config deployed to the IIS server, the API project runs fine and picks up the appsettings.Production.json settings that have the correct CorsOrigins settings and then the Angular client can connect.

So, this all boiled down to an environment variable that was set to "Development" in a web.config file that is not necessary in the API project.

I believe that if you will remove that web.config file from the download you generate, future customers will be able to publish to IIS and get CORS working without having to go through all this - assuming they set the system-wide ASPNETCORE_ENVIRONMENT=Production (or Staging if they are using the server for that) on the IIS server.

Well, launchSettings.json is a Visual Studio-only configuration file. It is only used when you are running or debugging the app from Visual Studio. At least that is how I understand it from Microsoft's documentation and my experience.

I don't believe that a web.config file is required at all for an Asp.Net Core API project. I don't understand why this one is in this project in the first place.

From my experience a web.config is only needed in a Core project (either API or MVC) when the project is published to an IIS web server. If the project will never be published to an IIS server, a web.config will likely never be needed.

Furthermore, during the publishing process, if not present, Visual Studio will automatically create the web.config file in the project's output directory and copy it to the IIS server. In this scenario the project will run on IIS but will never have a web.config in the project root. The publishing process just creates it in the output directory on the fly.

If there IS already a web.config file in the root of the project, then the Visual Studio publish will take it and make a copy and put in the output folder and then make some changes to the output copy that are required for the application to run on the target IIS server. But, the version in the root of the project will stay the same.

This is where the problem comes in with the current starting point of the AspNetZero project. The web.config that is already in the project root has ASPNETCORE_ENVIRONMENT=Development in it. So, that web.config is copied by the publish and that value is left as is when it gets sent to the IIS server. So, we end up with the application thinking it is running in development on the IIS Server and therefore uses the wrong appsettings.json file.

I believe the real solution is to remove the existing web.config file altogether from the root of the project. I think it is unnecessary and just causes a problem during publishing.

Anyway, that is the solution I am planning to test tomorrow.

Actually, I am not sure why that web.config file is needed in the API project in the first place. Can you please explain that to me?

I just create a plain ASP.NET Core 3.1 Web API project using the out-of-the-box VS 2019 template. It does not generate or require a web.config file to run using IIS Express on the dev machine:

Yes, it is an environment variable problem.

The fact that this web.config file ships with AspNetZero causes a System-wide ASPNETCORE_ENVIRONMENT=Production environment variable to be ignored on the IIS server when the web application runs:

I assume you ship the code this way because for debugging locally on IIS Express the web.config is needed and needs to be configured this way?

Anyway, it seems to me that for publishing the project to IIS one more piece of work needs to be done which is to set up a web.config transformation file per this page of Microsoft's documentation:

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/transform-webconfig?view=aspnetcore-3.1

With an environment (or configuration) specific web.config transformation, the correct environment variable value would be used in each environment.

If you agree with my analysis, I think you should add this to your documentation on this page, because its a pretty big "gotcha" in my opinion:

https://docs.aspnetzero.com/en/aspnet-core-angular/latest/Deployment-Angular-Publish-IIS

Jeff

Well, now I have found a discrepency between Microsofts ASP.NET Core 3.1 CORS documentation and ASP.NET Zero's implementation - in the 8.5.0 code at least.

Here is what Microsoft shows for Core 3.1:

Here is what is in the downloaded 8.5.0 code:

That string variable is set to this value:

So, according to the 3.1 documentation it would instead need to be:  options.AddPolicy(name: DefaultCorsPolicyName, builder =>

I am going to implement this tomorrow and see what results I get.  I already implemented it in a small test application I built and IT DID solve the problem in that application.

I have been trying different experiments today and am starting to wonder if IIS (I'm using v10 with Server 2019) really works with native ASP.NET Core CORS infrastucture in the scenario that is required in order to publish and run a multi-tenant AspNetZero API + Angular application.

When I say "native ASP.NET Core CORS infrastructure" I am talking about just using the built-in ASP.NET Core CORS functionality of the application and WITHOUT having to also use the IIS CORS Module extension.

I'm referring to this extension:

https://www.iis.net/downloads/microsoft/iis-cors-module

I've never used that extension before, but I guess I am going to have to try it because I am not getting anywhere at this point, even though I believe I have followed Volosoft's documentation to the letter.

I guess the other option is to try to push the application up to Azure to see if it will run there, and that is our ultimate goal for production, but we also need an internal server that the system testing team can do pre-production testing on and that's why I need to get this to run on IIS as well.

Jeff

I had already tried that, but just tried it again. It doesn't seem to make any difference. The error is still "No 'Access-Control-Allow-Origin' header is present on the requested resource".

Here is the appsettings.production.json:

On the host logs this is still the same error message:

Showing 11 to 20 of 41 entries