Base solution for your next web application
Starts in:
01 DAYS
01 HRS
01 MIN
01 SEC

Activities of "mightyit"

Yes, but I'm not sure whether I am doing it right. Here is the code I am using for this just before calling tokenAuthClient.ImpersonatedAuthenticateAsync (and still getting the same error as mentioned above):

_httpClient.DefaultRequestHeaders.Remove("Abp.TenantId");
_httpClient.DefaultRequestHeaders.Add("Abp.TenantId",selectedTenantId.ToString());

I have also tried to modify the header for the HttpRequestMessage inside the generated client as follows,with the same outcome:

request_.Headers.Remove("Abp.TenantId");
request_.Headers.Add("Abp.TenantId", selectedTenantId?.ToString());

@ryancyq The provided link gives a 404 error

I am writing a utility that allows a host user to do batch loading of data on behalf of a tenant, via our API. For this, I have generated a .Net Core 2.2 client with NSwag, based on the generated swagger docs. This of course means that we use TokenAuth for authentication.

I am getting stuck with impersonation though. I am able to get an impersonation token, but get stuck when I want to authenticate as the impersonated user & tenant.

Here is my code through which I invoke the generated TokenAuth client:

// Get the impersonation token...
var accountClient = new AccountClient(_baseUri, _httpClient);
var impersonationToken = (await accountClient.ImpersonateAsync(new ImpersonateInput
{
    TenantId = selectedTenantId,
    UserId = selectedUserId,
})).ImpersonationToken;
            
var tokenAuthClient = new TokenAuthClient(_baseUri, _httpClient);            
var impersonatedAccessToken =
    (await tokenAuthClient.ImpersonatedAuthenticateAsync(impersonationToken)).AccessToken; // <== This call is generating Http Error 500

In my Web.Core project, the ImpersonatedAuthenticate method is being called on TokenAuthController as follows:

[HttpPost]
public async Task<ImpersonatedAuthenticateResultModel> ImpersonatedAuthenticate(string impersonationToken)
{
    var result = await _impersonationManager.GetImpersonatedUserAndIdentity(impersonationToken); <== This line is generating the exception
    var accessToken = CreateAccessToken(await CreateJwtClaims(result.Identity, result.User));

    return new ImpersonatedAuthenticateResultModel
    {
        AccessToken = accessToken,
        EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
        ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
    };
}

Here is the exception I am getting:

Further details:

  • I'm using the AspNetCore + JQuery version of the framework
  • Abp.AspNetZeroCore 1.2.2
  • Abp.ZeroCore 4.4.0

Swashbuckle depends on ApiExplorer, and the use of the ApiExplorer attribute limits us to specifying only a single groupname per controller / action. As per @ryancyq above, "service proxies are generated via NSwag for angular project." and it seems that during this process a dependency is broken.

The workaround was to create my own attribute for delimiting one-or-more groupnames for an appservice controller or action, and subsequently use reflection in my DocInclusionPredicateFunction to retrieve the groupnames for an action or its containing controller.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class SwaggerDocAttribute: Attribute
{
    public SwaggerDocAttribute(params string[] includeInDocuments)
    {
        IncludeInDocuments = includeInDocuments;
    }

    public string[] IncludeInDocuments { get; }
}

options.DocInclusionPredicate((docName, apiDesc) =>
{
    if (!apiDesc.ActionDescriptor.IsControllerAction())
    {
        return false;
    }

    apiDesc.TryGetMethodInfo(out MethodInfo methodInfo);

    var actionDocs = methodInfo.GetCustomAttributes<SwaggerDocAttribute>()
        .SelectMany(a => a.IncludeInDocuments);

    var controllerDocs = methodInfo.DeclaringType.GetCustomAttributes<SwaggerDocAttribute>()
        .SelectMany(a => a.IncludeInDocuments);

    switch (docName)
    {
        case "HostApiv1":
            return apiDesc.GroupName == null || 
            actionDocs.Contains("HostApiv1") || 
            controllerDocs.Contains("HostApiv1");
        case "TenantApiv1":
            return apiDesc.GroupName == null ||
            actionDocs.Contains("TenantApiv1") || 
            controllerDocs.Contains("TenantApiv1");
        default:
            return true;
    }
});

Usage

[DisableAuditing]
[AbpAuthorize(AppPermissions.HostSpecific.Dashboard.Access)]
//[ApiExplorerSettings(GroupName = "HostApiv1")]
[SwaggerDoc("HostApiv1")]
public class HostDashboardAppService : ZenDetectAppServiceBase, IHostDashboardAppService
{
        //...
}

@ryancyq @ismcagdas That works insofar my swagger documentation is concerned, however, it now seems that whenever an app service is decorated with either [ApiExplorerSettings(GroupName = "HostApiv1")] or [ApiExplorerSettings(GroupName = "TenantApiv1")], my client side dependencies on those services are broken. It seems that somehow AbpServiceProxies has a dependency on Swagger generation?

See below:

I have created two OpenApi specifications (HostApiv1 and TenantApiv1) as follows in Startup.cs:

services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("HostApiv1", new Info { Title = "Host API v1", Version = "v1" });
    options.SwaggerDoc("TenantApiv1", new Info { Title = "Tenant API v1", Version = "v1" });

    options.DocInclusionPredicate((docName, description) => true);
    options.IgnoreObsoleteActions();
    options.IgnoreObsoleteProperties();
    options.OrderActionsBy((apiDesc) => $"{apiDesc.RelativePath}");
    options.DescribeAllEnumsAsStrings();
});
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint(_appConfiguration["App:HostApiSwaggerEndPoint"], "Host API v1");
    options.SwaggerEndpoint(_appConfiguration["App:TenantApiSwaggerEndPoint"], "Tenant API v1");
    //...
});

However, when I decorate my AppService classes with [ApiExplorerSettings(GroupName = "HostApiv1")], the grouping is ignored and the tag (AppService controller), along with all of its operations (actions / methods), still appear under both documents.

Please advise.

Hi @ismcagdas

No. I had to use workarounds.

@alper

Yes, that's a typo. It should be (and is) ITransientDependency.

OK, interesting....

  • Explicitly injecting IUnitOfWork, as you suggested, seems to work.
  • Running with the attribute [UnitOfWork(IsDisabled = true)] throws the original exception

Why would the IUnitOfWork not resolve for the BackgroundJob<TArgs> base class? How do I go about fixing it?

Hi @alper

Thanks for the assistance. I have tried both ways, unsuccesfully unfortunately.

However, when I did this...

 [UnitOfWork]
 public override void Execute(TroubleshootingBackgroundJobArgs args) 
 { 
       using(var uow = UnitOfWorkManager.Begin()) // <== Exception generated here...
       {
             repository.GetAll().ToList();
             uow.Complete();
       }   
 }

.... I got the following exception:

Abp.AbpException HResult=0x80131500 Message=Must set UnitOfWorkManager before use it. Source=Abp StackTrace: at Abp.BackgroundJobs.BackgroundJob1.get_UnitOfWorkManager() at Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList.Infrastructure.Persons.PersonMonitoringBatch.PersonMonitoringBatchSearchJob.ExecuteJob(PersonMonitoringBatchSearhJobArgs args) in D:\Projects\ZenDetect\Modules\Sanctions\Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList\Infrastructure\Persons\PersonMonitoringBatch\PersonMonitoringBatchSearchJob.cs:line 54 at Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList.Core.BatchSearchJobBase1.Execute(TBatchSearhJobArgs args) in D:\Projects\ZenDetect\Modules\Sanctions\Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList\Core\BatchSearchJobBase.cs:line 20

Seems like the Unit of Work object is not resolving, for some reason?

Showing 21 to 30 of 66 entries