Base solution for your next web application

Activities of "maharatha"

To start with I am in love with Abp and AbpZero. Awesome Job @hikalkan.

I have read the previous article of extending the session ields :

#584@1182f777-3cd5-40b6-82d9-19e91497527f

I found the easiest way to do is to add claims directly but I don't think that's the smartest way to do it.

Could you provide an example with implementation as I am sure this is going to help a lot of people ? I am actually planning to store the organization ID for a user.

This is how I am adding claims :

var identity = await UserManager.CreateIdentityAsync(GetCurrentUser(), DefaultAuthenticationTypes.ApplicationCookie);

identity.AddClaim(new Claim("OrganizationId", "2"));

This is how I am trying to get the claim :

public class MyAppSession : IdentityFrameworkClaimsAbpSession {

    // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
    private readonly UserManager _userManager;

    public MyAppSession(UserManager userManager, IMultiTenancyConfig multiTenancy) : base(multiTenancy)
    {
        
        _userManager = userManager;
    }

   
    public static long? OrganizationId
    {
        get
        {

            
            var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
            if (claimsPrincipal == null)
            {
                return null;
            }

            var claimsIdentity = claimsPrincipal.Identity as ClaimsIdentity;
            if (claimsIdentity == null)
            {
                return null;
            }
            
            var OrgIdClaim = claimsIdentity.Claims.FirstOrDefault(c => c.Type == "OrganizationId");
            if (OrgIdClaim == null || string.IsNullOrEmpty(OrgIdClaim.Value))
            {
                return null;
            }

            long orgId;
            if (!long.TryParse(OrgIdClaim.Value, out orgId))
            {
                return null;
            }

            return orgId;
        }
      
    }



    
}

I am unable to get the claim :

Am I doing anything wrong ?

Awesome !! Worked for me.

I am currently starting a new project so such quick response is very much appreciated.

Thank You Again .

My project has the requirement where one single user can be associated with multiple companies. This is taken care by AspnetZero. I think it would be useful if we have the following items implemented as well :

  1. Setting a default Organization to an user
  2. Associating that Organization when the user logs in. Presently a user when logs in is not associated with any organization
  3. Allowing an user to switch organization

When we add or do any activity the system automatically updates the TenantID in DB , but I don't see any such provision for Organization, probably for the lack of above implementation.

I was going through the below post :

#488@8b17fa78-f26f-44a4-bd4f-1ea5b00d5f75

But couldn't find an answer. But my requirement is more or less similar.

I want to use all inbuild functionality of ASPNET ZERO but I would like to save all tenant related information other than implemented by AspnetZero to be stored in it's own DB.

To be more specific I want all transnational data (like vendor,customer,etc) to be stored in a separate database for each Tenant.

<a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/MultipleDbContextDemo">https://github.com/aspnetboilerplate/as ... ontextDemo</a> : This is a solution which enables me to seggregate the data.

The problem is I want to programatically change the DBContext connection string based on TenantID. I am unable to access ASPNetZero Sessions outside DBcontext contructor , so I am not sure how to use this to pass the correct connection string. Moreover I am also unable to access Session in my DbContext class. So the hwole question revolves around how to access the TenantID so that I can get the connection string and pass on to the database.

public class TesTrans : AbpDbContext { /* Setting "Default" to base class helps us when working migration commands on Package Manager Console. * But it may cause problems when working Migrate.exe of EF. ABP works either way. * */ public virtual IDbSet<COAUnit> COAUnit { get; set; }

    // public virtual IDbSet&lt;AddressUnit&gt; AddressUnit { get; set; }
    
   

<span style="color:#BF00BF">// nameOrConnectionString - How to set this connection string as I am unable to access ABPSession or any session </span> public TesTrans (string nameOrConnectionString) : base(nameOrConnectionString) {

    }

    /* This constructor is used by ABP to pass connection string defined in CORPACCOUNTINGDataModule.PreInitialize.
     * Notice that, actually you will not directly create an instance of TesTrans since ABP automatically handles it.
     */
    

}

Also I was trying to get the TenantID inside my DBContext constructor and it was coming as Null. But as far as I know you should be able to get AbpSession.TenantID values if you are using AspnetZero which I am currently using.

Any help is really appreciated.

Thank You for the response. Yes if OU are extended more in ASPNET Zero I am sure it would be helpful for everyone in the community.

I am now using Claims to store the connection string and using it this way :

public TesTrans(string nameOrConnectionString): base(GetDynamicConnectionString()) { }

    public static string GetDynamicConnectionString()
    {
        var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
        if (claimsPrincipal == null)
        {
            return null;
        }


        var claimsIdentity = claimsPrincipal.Identity as ClaimsIdentity;

        if (claimsIdentity == null)
        {
            return null;
        }

        var ConnStringClaim = claimsIdentity.Claims.FirstOrDefault(c => c.Type == "ConnString");
        if (ConnStringClaim == null || string.IsNullOrEmpty(ConnStringClaim.Value))
        {
            return null;
        }

        return ConnStringClaim.Value;
    }

in my DBContext.

Is this the right way of approach and is there a cleaner and better approach ?

Thank You Hikalkan. You are a savior 8-) . I will be storing the connection string in a DB table and will be getting the connection string from the table and storing in claims,. As the connection string will keep getting added so not sure if I can store that in a static class using dictionary and it would be one connection string per tenant or user. Correct me if I am wrong in my approach ? I am learning a lot of Aspnet Boiler and wants to keep learning.

Secondly I could access the Abpsession using constructor injection but couldn't use it as I wanted the TenantID to be passed as a parameter to GetDynamicConnectionString() which i couldn't. Also I couldn't use the AbpSession.TenantID inside GetDynamicConnectionString() as it's called before the contructor

Lastly, I am unable to find out one common place where I should add my claims because the connection string would change when the host will impersonate. I was trying in AccountController.cs in SaveImpersonationTokenAndGetTargetUrl method for adding and updating claims but when an user impersonates he impersonates as another user. So the claims for impersonated user is null. Basically where should I set claims for impersonated user.

Thanks in advance.

Finally I did the implementation without adding any new claims. Below is what I did :

Created a Static class containing a static dictionary storing the tenant ID and the DB Connection .

static class ConnectionStrings { static Dictionary<int, string> _dict = new Dictionary<int, string> { {1, @"Server =.\xxxxxx; Database = xxxxxxxx; Trusted_Connection = True;"}, {2, @"Server =.\xxxx; Database = xxxxxxxyyy; Trusted_Connection = True;"},

};

    /// &lt;summary&gt;
    /// Access the Dictionary from external sources
    /// &lt;/summary&gt;
    public static string GetConnectionString(int intTenantID)
    {
        // Try to get the result in the static Dictionary
        string result;
        if (_dict.TryGetValue(intTenantID, out result))
        {
            return result;
        }
        else
        {
            return @"Server =.\xxxxx; Database = cxxxxxxxxx; Trusted_Connection = True;";
        }
    }
}

Then Created a Method called GetDynamicConnectionString()

Was able to access the TenantID using :

var ConnStringClaim = claimsIdentity.Claims.FirstOrDefault(c => c.Type == "http://www.aspnetboilerplate.com/identity/claims/tenantId");

Showing 1 to 10 of 326 entries