Activities of "EngincanV"

Hi Chris, thank you for your detailed explanation and for clarifying the scenario. I don't have much experience with Azure Blob Storage but I'll try to clarify some points for you.

1. Recommended Approach in ABP Framework

As far as I know, you should be able to implement tenant/module/entity level separation by customizing the container naming convention. By default, IAzureBlobNameCalculator is used to calculate the full BLOB name, so you can create a service that implements this interface and apply your own logic. You can check the DefaultAzureBlobNameCalculator (https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/DefaultAzureBlobNameCalculator.cs) service for the current implementation. (Currently, the naming is something like: tenants/<tenant-id>)

2) Centralized Configuration

For the configuration, you can refer to our documentation: https://abp.io/docs/latest/framework/infrastructure/blob-storing/azure#configuration (when it's being configured for default, it applies to all)

3) Overriding ABP Suite’s Scaffolding

Currently, you can search for File text in the ABP Suite's templates and update the .txt files. Unfortunately, this is the only option you have for now, or you need to update the code later the code generation manually.

4) Manual Implementation and Best Practices

If you are considering creating your own file-manager services, I recommend using the IBlobContainer service to make it provider-agnostic, so you can change the provider afterward if it's needed.

On the other hand, it depends on how you structure your solution and services. I'm not sure that I have a suggestion at that point.


Btw, it is worth reiterating that, once the Azure Blob Provider is configured, the system is expected to behave as follows:

When a file is uploaded, a new record containing the file’s metadata is inserted into the *FileDescriptors table in the database, while the file content is stored in Azure Blob Storage. Subsequently, when the file is needed, the IBlobContainer service retrieves it from Azure and returns it to the requesting component.

[sghorakavi@cpat.com] said:

[EngincanV] said: Yes, you need to have 4 routes. In the front-facing route, nginx should listen and forward to the related underlying service.

Can you pls review nginx reverse proxy? It is not working as planned.

#user  nobody; 
worker_processes  1; 
 
#error_log  logs/error.log; 
#error_log  logs/error.log  notice; 
#error_log  logs/error.log  info; 
 
#pid        logs/nginx.pid; 
 
 
events { 
    worker_connections  1024; 
} 
 
 
http { 
    include       mime.types; 
    default_type  application/octet-stream; 
 
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ' 
    #                  '$status $body_bytes_sent "$http_referer" ' 
    #                  '"$http_user_agent" "$http_x_forwarded_for"'; 
 
    #access_log  logs/access.log  main; 
 
    sendfile        on; 
    #tcp_nopush     on; 
 
    #keepalive_timeout  0; 
    keepalive_timeout  65; 
 
    #gzip  on; 
 
 
    server { 
        listen       44500; 
        server_name  localhost; 
 
        #charset koi8-r; 
 
        #access_log  logs/host.access.log  main; 
 
        location / { 
            root   html; 
            index  index.html index.htm; 
            proxy_pass https://localhost:44385;  
      proxy_ssl_verify off; 
 
        } 
  # Reverse proxy to your ABP Host API app 
    	location /hostapi/ { 
                proxy_pass         https://localhost:44348; 
                proxy_http_version 1.1; 
                proxy_ssl_verify off;                 
 
                proxy_set_header   Host $host; 
                proxy_set_header   X-Real-IP $remote_addr; 
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for; 
                proxy_set_header   X-Forwarded-Proto $scheme; 
                proxy_set_header   X-Forwarded-Prefix /hostapi;   
 
                # WebSocket / Hot Reload support 
                proxy_set_header   Upgrade $http_upgrade; 
                proxy_set_header   Connection "upgrade"; 
        } 
   
  location /auth/ { 
                proxy_pass         https://localhost:44394; 
                proxy_http_version 1.1; 
                proxy_ssl_verify off;                 
 
                proxy_set_header   Host $host; 
                proxy_set_header   X-Real-IP $remote_addr; 
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for; 
                proxy_set_header   X-Forwarded-Proto $scheme; 
                proxy_set_header   X-Forwarded-Prefix /hostapi;   
 
                # WebSocket / Hot Reload support 
                proxy_set_header   Upgrade $http_upgrade; 
                proxy_set_header   Connection "upgrade"; 
        } 
 
        #error_page  404              /404.html; 
 
        # redirect server error pages to the static page /50x.html 
        # 
        error_page   500 502 503 504  /50x.html; 
        location = /50x.html { 
            root   html; 
        } 
 
   
        
    } 
 
} 

Added forward header option in host module

I am attempting to invoke: https://localhost:44500 - web https://localhost:44500/hostapi - host api https://localhost:44500/auth - Auth

Hi, it seems there are a few mistakes in the nginx.config:

  1. In /auth route forwarding, you have used a line: proxy_set_header X-Forwarded-Prefix /hostapi, it should be proxy_set_header X-Forwarded-Prefix /auth
  2. You should use a trailing slash at the end of proxy_pass lines: proxy_pass https://localhost:44348/;
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;


    server {
        listen       44500;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
        
        # Redirect no-trailing-slash to with-slash so the /hostapi/ and /auth/ blocks match
        location = /hostapi { return 301 /hostapi/; }
        location = /auth    { return 301 /auth/; }

        location / {
            proxy_pass https://localhost:44385/;
            proxy_http_version 1.1;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection "upgrade";
            proxy_ssl_verify off;

        }
	    # Reverse proxy to your ABP Host API app
    	location /hostapi/ {
                proxy_pass         https://localhost:44348/;
                proxy_http_version 1.1;
                proxy_ssl_verify off;                

                proxy_set_header   Host $host;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;
                proxy_set_header   X-Forwarded-Prefix /hostapi;  

                # WebSocket / Hot Reload support
                proxy_set_header   Upgrade $http_upgrade;
                proxy_set_header   Connection "upgrade";
        }
	
	location /auth/ {
                proxy_pass         https://localhost:44394/;
                proxy_http_version 1.1;
                proxy_ssl_verify off;                

                proxy_set_header   Host $host;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;
                proxy_set_header   X-Forwarded-Prefix /auth;  

                # WebSocket / Hot Reload support
                proxy_set_header   Upgrade $http_upgrade;
                proxy_set_header   Connection "upgrade";
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

	
       
    }

}

Also, ensure you made the correct configs in the appsettings.json files for your projects.

Yes, you need to have 4 routes. In the front-facing route, nginx should listen and forward to the related underlying service.

[sghorakavi@cpat.com] said: Can you pls send me ABP MVC multi layer sample that can handle above port situation ? We are planning to use one domain and we will use reverse proxy.

https://localhost:44356/auth -- auth server https://localhost:44356/hostapi - hostapi server https://localhost:44356 - web server

Thank you

Hi, actually, this is not fully related to ABP, but it's related to your application and nginx configs. So, you may need to work on that manually. However, I can explain what should be done step by step and clarify some steps for you:

  1. Call the following middleware before other middlewares in your application (it should already be configured in your auth-server project):
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
  1. You basically need 4 ports: one for nginx (front), web, auth-server and hostapi. (I assume: 44356 for nginx-front side, and then 44378 for web , 44339 for auth-server and 44342 for hostapi). Configure your nginx.config file accordingly:
events {}

http {
    server {
        listen 44356;

        location / {
            proxy_pass http://localhost:44378;
        }

        location /auth/ {
            proxy_pass http://localhost:44339/;
        }

        location /hostapi/ {
            proxy_pass http://localhost:44342/;
        }
    }
}
  1. Update the relevant appsettings.json files for each project:

Web:

{
  "App": {
    "SelfUrl": "https://localhost:44356", //UPDATED
    "DisablePII": false,
    "HealthCheckUrl": "/health-status"
  },
  "RemoteServices": {
    "Default": {
      "BaseUrl": "https://localhost:44356/hostapi/" //UPDATED
    },
    "AbpAccountPublic": {
      "BaseUrl": "https://localhost:44356/auth/" //UPDATED
    }
  },
  "AuthServer": {
    "Authority": "https://localhost:44356/auth", //UPDATED
    "RequireHttpsMetadata": true,
    "ClientId": "AbpNginxDemo_Web",
    "ClientSecret": "1q2w3e*"
  },
 }

Auth-server (optional, and also update cors-origins accordingly):

  "App": {
    "SelfUrl": "https://localhost:44356/auth",
    //...
  },
  "AuthServer": {
   "Authority": "https://localhost:44356/auth"
  }

HttpApiHost:

{
  "App": {
    "SelfUrl": "https://localhost:44356/hostapi",
    //...
  },
  "AuthServer": {
    "Authority": "https://localhost:44356/auth",
    "RequireHttpsMetadata": true,
    "MetaAddress": "https://localhost:44356/auth",
    //...
  },
}
  1. Then, if your configurations are correct, it should work as expected.

Also, for this problem, the IIS page means you’re trying to run more than one ASP.NET Core app “in-process” in the same IIS Application Pool, which isn’t supported. You can search for this error on Stack Overflow and see the possible solutions.

Regards.

[chrisalves] said: Hi Engincan,

Thank you for your response.

Let’s keep this ticket open for a few more days while I review the point and run some test scenarios based on your suggestions.

Best regards,

Sure 👍

[sghorakavi@cpat.com] said:

[EngincanV] said:

[sghorakavi@cpat.com] said: Laucnchsettings.json{"iisSettings": {"windowsAuthentication": false,"anonymousAuthentication": true,"iisExpress": {"applicationUrl": "https://localhost:44356/hostapi","sslPort": 44356}},"profiles": {"IIS Express": {"commandName": "IISExpress","launchBrowser": true,"environmentVariables": {"ASPNETCORE_ENVIRONMENT": "Development","DOTNET_WATCH": "false"

  }   
},   
"Approach.HttpApi.Host": {   
  "commandName": "Project",   
  "launchBrowser": true,   
  "applicationUrl": "https://localhost:44356/hostapi",   
  "environmentVariables": {   
    "ASPNETCORE_ENVIRONMENT": "Development"   
 
  }   
}   

}}

-added frowardheader

My swagger.json looks fine but swagger.html is not opening swagger.json. It cannot find hostapi in the path.

My appsettings.json has

"App": {"SelfUrl": "https://localhost:44356/hostapi","CorsOrigins": "https://*.Approach.com;https://localhost:44356/hostapi","DisablePII": false,"HealthCheckUrl": "/health-status"},

In the module:

app.UsePathBase("/hostapi");

app.UseAbpSwaggerUI(options =>{options.SwaggerEndpoint("/swagger/v1/swagger.json", "Approach API");options.RoutePrefix = "swagger";

var configuration = context.GetConfiguration();   
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);   

});

Can you pls let me know what did I miss. Do you need any other information ?

I started with sample ABP, MVC multi layer application.I need Host Service to open https://localhost:44356/hostapi/swagger/index.html properly.Thank you

Hi, I don't see any reverse-proxy configuration here. Instead, I only notice the code line app.UsePathBase("/hostapi");, which sets the path-base and makes your application endpoints in the following format: /hostapi/<remaining-routes>

And it seems this is not what you want, and I would not call it a reverse proxy, because it only sets the path-base and transforms the URLs. It does not redirect to an underlying service; for this purpose, you need a reverse proxy (If you need to expose all of your different apps that are running in different ports in the same port with distinct route configs, you need to use a reverse proxy like nginx, for example.)

An example config for nginx:

events {}  
  
http {  
    server {  
        listen 44378 ssl;  
        server_name localhost;  
  
        # 🔐 SSL certificate (use your own dev or real certs) (optional)  
        ssl_certificate     /path/to/dev-cert.pem;  
        ssl_certificate_key /path/to/dev-key.pem;  
  
        # Common headers  
        proxy_set_header Host               $host;  
        proxy_set_header X-Real-IP          $remote_addr;  
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;  
        proxy_set_header X-Forwarded-Proto  $scheme;  
  
        # Allow large bodies (optional)  
        client_max_body_size 50m;  
  
        # ===== /api → Host Server =====  
        location /api/ {  
            proxy_pass https://localhost:44342/;  
            proxy_ssl_verify off;  
        }  
  
        # ===== /auth → Auth Server =====  
        location /auth/ {  
            proxy_pass https://localhost:44339/;  
            proxy_ssl_verify off;  
        }  
  
        # ===== / → Web Server =====  
        location / {  
            proxy_pass https://localhost:44378;  
            proxy_ssl_verify off;  
        }  
    }  
}  

With this config, nginx ensures, when you send a request to the https://localhost:44378/api, it redirects to the underlying service: https://localhost:44342.


If you just want to configure the hostpath, let me know, but in the current scenario you want, you need to use a reverse proxy.

Ok, I have nginx setup on my windows computer. The host server is working fine. There is authentication issue. After adding reverse proxy using nginx, I see this issue. Any suggestion ?

Hi, your nginx config seems right. To address the problem in your auth-server project, can you share its logs, please?

[nhontran] said: ABP Framework is currently referencing the latest version of Select2. However, it appears that there is no active maintenance for the Select2 library at this time. Is there any recommended workaround for this vulnerability, or does the ABP team have plans to replace Select2 with a more actively maintained alternative in future releases?

Hi, currently we are not considering replacing Select2. Even though it's not maintained actively, it's a stable and popular library. If you want us to replace it with another alternative, please don't hesitate to create an issue at https://github.com/abpframework/abp/issues, so we can discuss and consider.

In the link you provided, I see some suggestions to overcome the XSS vulnerability. I'll check our select2 implementation and check what we can do.

Thanks for reporting.

[sghorakavi@cpat.com] said: Laucnchsettings.json { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "https://localhost:44356/hostapi", "sslPort": 44356 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_WATCH": "false"

  } 
}, 
"Approach.HttpApi.Host": { 
  "commandName": "Project", 
  "launchBrowser": true, 
  "applicationUrl": "https://localhost:44356/hostapi", 
  "environmentVariables": { 
    "ASPNETCORE_ENVIRONMENT": "Development" 

  } 
} 

} }

-added frowardheader

My swagger.json looks fine but swagger.html is not opening swagger.json. It cannot find hostapi in the path.

My appsettings.json has

"App": { "SelfUrl": "https://localhost:44356/hostapi", "CorsOrigins": "https://*.Approach.com;https://localhost:44356/hostapi", "DisablePII": false, "HealthCheckUrl": "/health-status" },

In the module:

app.UsePathBase("/hostapi");

app.UseAbpSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Approach API"); options.RoutePrefix = "swagger";

var configuration = context.GetConfiguration(); 
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); 

});

Can you pls let me know what did I miss. Do you need any other information ?

I started with sample ABP, MVC multi layer application. I need Host Service to open https://localhost:44356/hostapi/swagger/index.html properly. Thank you

Hi, I don't see any reverse-proxy configuration here. Instead, I only notice the code line app.UsePathBase("/hostapi");, which sets the path-base and makes your application endpoints in the following format: /hostapi/<remaining-routes>

And it seems this is not what you want, and I would not call it a reverse proxy, because it only sets the path-base and transforms the URLs. It does not redirect to an underlying service; for this purpose, you need a reverse proxy (If you need to expose all of your different apps that are running in different ports in the same port with distinct route configs, you need to use a reverse proxy like nginx, for example.)

An example config for nginx:

events {}

http {
    server {
        listen 44378 ssl;
        server_name localhost;

        # 🔐 SSL certificate (use your own dev or real certs) (optional)
        ssl_certificate     /path/to/dev-cert.pem;
        ssl_certificate_key /path/to/dev-key.pem;

        # Common headers
        proxy_set_header Host               $host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;

        # Allow large bodies (optional)
        client_max_body_size 50m;

        # ===== /api → Host Server =====
        location /api/ {
            proxy_pass https://localhost:44342/;
            proxy_ssl_verify off;
        }

        # ===== /auth → Auth Server =====
        location /auth/ {
            proxy_pass https://localhost:44339/;
            proxy_ssl_verify off;
        }

        # ===== / → Web Server =====
        location / {
            proxy_pass https://localhost:44378;
            proxy_ssl_verify off;
        }
    }
}

With this config, nginx ensures, when you send a request to the https://localhost:44378/api, it redirects to the underlying service: https://localhost:44342.


If you just want to configure the hostpath, let me know, but in the current scenario you want, you need to use a reverse proxy.

[kkmy] said: Hi EngincanV,

The code that you provided for the method is not like this in my project and the new project that is created with the version 9.3.5 recently. The following is how the particular method is created:

private void ConfigureAuthentication(ServiceConfigurationContext context) 
{ 
    context.Services.ForwardIdentityAuthenticationForBearer( 
        OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme 
    ); 
    context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options => 
    { 
        options.IsDynamicClaimsEnabled = true; 
    }); 
} 

It appears that you do not have a separate authentication server application. My previous code example assumed the existence of both the AuthServer project and the HttpApiHost project as separate components. However, it appears that only the HttpApiHost project is present, likely in a unified configuration.

In that case, you may use the following code in your application:

        Configure<JwtBearerOptions>(options =>
        {
            options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    AlgorithmValidator = (algorithm, securityKey, securityToken, validationParameters) =>
                    {
                        return !algorithm.Equals("none", StringComparison.OrdinalIgnoreCase);
                    }
                };
        });

This code should be placed prior to invoking the ConfigureAuthentication method. Doing so should ensure proper functionality.

Hi, you can ignore the response of the AI bot.

If you open your *HttpApi.Host project and search for the ConfigureAuthentication method, then you'll notice there is a configuration as follows:

    private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddAbpJwtBearer(options =>
            {
                options.Authority = configuration["AuthServer:Authority"];
                options.RequireHttpsMetadata = configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata");
                options.Audience = "<your-project-name>";
                
                //WRITE THE BELOW CODE HERE!!!
            });

        context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
        {
            options.IsDynamicClaimsEnabled = true;
        });
    }

Here, you can configure TokenValidationParameters and make the relevant validations for the token. In your case, a code like this should work:

options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    AlgorithmValidator = (algorithm, securityKey, securityToken, validationParameters) =>
                    {
                        return !algorithm.Equals("none", StringComparison.OrdinalIgnoreCase);
                    }
                };

AlgorithmValidator checks if the alg header is as expected with the specified algorithm or not.

Showing 1 to 10 of 1370 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on October 30, 2025, 06:33