Base solution for your next web application
Open Closed

Access TenantId to Filter & CRUD with separate database #2269


User avatar
0
OutdoorEd created

I am using ASP.NET Zero as the authentication platform for a multi-tenant application. Once logged in individual tenants submit accident data to a separate database. I need to do two things with TenantId.

  1. Filter accident data by TenantId so that each Tenant can only view their own data. I have a TenantId as a field in the Accident table. I think this can be done in my AccidentModel using some code for EntityFramework.Dynamic Filters but do not know how to implement the code.

  2. I need to be able to access the TenantID as a Claim or Session variable for CRUD operations and don't know what code I would need to do that.

Thank you


3 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Can you share your accident entity definition ? If you are doing the operations like filtering accident data or saving a new accident after authentication, accident data must be filtered by logged in tenant automatically.

    When you save a new accident, it's tenantId must be set automatically as well.

    So, if you can share your accident entity definition, we can understand the problem.

    Thanks.

  • User Avatar
    0
    OutdoorEd created

    There are dozens of child tables so I've simplified the model to show a short version the main parent table INCIDENT and just one child table - COMMUNICATIONLOG. TenantId is saved in the Incidents Table and also is saved in all the child tables. Having TenantId in all child tables provides row level security.

    INCIDENTS namespace OE_Tenant.Web.Areas.Incidents.Models { using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.Spatial;

    [Table("idb_Incident")]
    public partial class Incident
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Incident()
        {
            CommunicationLog = new HashSet<CommunicationLog>();
        }
    
        [Key]
        public Guid IncidentId { get; set; }
    
        [UIHint("GridForeignKey")]
        public int IncidentCategoryId { get; set; }
    
        [Required]
        [Column(TypeName = "smalldatetime")]
        public DateTime? IncidentDate { get; set; }
    
        [Required]
        [StringLength(200)]
        public string IncidentEvent { get; set; }
    
        [UIHint("GridForeignKey")]
        public int IncidentTypeId { get; set; }
    
        [Column(TypeName = "datetime2")]
        public DateTime DateEntered { get; set; }
    
    	[Column(TypeName = "datetime2")]
        public DateTime? DateUpdated { get; set; }
    
        public int TenantId { get; set; }
    
        public virtual LkpIncidentCategory LkpIncidentCategory { get; set; }
    
        public virtual LkpIncidentType LkpIncidentType { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<CommunicationLog> CommunicationLog { get; set; }
    
    }
    

    }

    COMMUNICATIONLOG

    using System.ComponentModel;

    namespace OE_Tenant.Web.Areas.Incidents.Models

    { using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.Spatial;

    [Table("idb_CommunicationLog")]
    public partial class CommunicationLog
    {
    
        [Key]
        public Guid CommunicationLogId { get; set; }
    
        [DisplayName("Communication Type")]
        [UIHint("GridForeignKey")]
        public int CommunicationTypeId { get; set; }
    
        [DisplayName("Direction")]
        [UIHint("GridForeignKey")]
        public int CommunicationDirectionId { get; set; }
    
        public Guid IncidentId { get; set; }
    
        [DataType(DataType.Date)]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
        public DateTime? Date { get; set; }
    
        [DataType(DataType.Time)]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:t}")]
        public TimeSpan? StartTime { get; set; }
    
        [DataType(DataType.Time)]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:t}")]
        public TimeSpan? EndTime { get; set; }
    
        [StringLength(50)]
        public string FirstName { get; set; }
    
        [StringLength(50)]
        [Display(Name = "Last Name", Prompt = "Enter person's last name")]
        public string LastName { get; set; }
    
        [StringLength(200)]
        public string Address1 { get; set; }
    
        [StringLength(100)]
        public string CountryCode { get; set; }
    
        [Column(TypeName = "datetime2")]
        public DateTime DateEntered { get; set; }
    
        [Column(TypeName = "datetime2")]
        public DateTime DateUpdated { get; set; }
    
        public int TenantId { get; set; }
    
        public virtual LkpCommunicationDirection LkpCommunicationDirection { get; set; }
    
        public virtual LkpCommunicationType LkpCommunicationType { get; set; }
    
        public virtual Incident Incident { get; set; }
    
        public virtual LkpCountry LkpCountry { get; set; }
    }
    

    }

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Adding TenantId to your entity manually does not do anything about multi teancy. You need to implement IMayHaveTenant or IMustHaveTenant interface on your entity. In this way ABP framework can understand and apply multi tenancy filters.

    You can read this doc for more information <a class="postlink" href="http://aspnetboilerplate.com/Pages/Documents/Multi-Tenancy">http://aspnetboilerplate.com/Pages/Docu ... ti-Tenancy</a>. Especially for your case read <a class="postlink" href="http://aspnetboilerplate.com/Pages/Documents/Multi-Tenancy#data-filters">http://aspnetboilerplate.com/Pages/Docu ... ta-filters</a>.

    After implementing one of those interfaces on your entity, add and apply a new migration. Then it should work like you wanted.