Abstract version of OrganizationUnit would be nice...
/// <summary>
/// Represents an organization unit (OU).
/// </summary>
public abstract class OrganizationUnitBase<TSelf> : FullAuditedEntity<long>, IMayHaveTenant
{
/// <summary>
/// Maximum length of the <see cref="DisplayName"/> property.
/// </summary>
public const int MaxDisplayNameLength = 128;
/// <summary>
/// Maximum depth of an UO hierarchy.
/// </summary>
public const int MaxDepth = 16;
/// <summary>
/// Length of a code unit between dots.
/// </summary>
public const int CodeUnitLength = 5;
/// <summary>
/// Maximum length of the <see cref="Code"/> property.
/// </summary>
public const int MaxCodeLength = MaxDepth * (CodeUnitLength + 1) - 1;
/// <summary>
/// TenantId of this entity.
/// </summary>
public virtual int? TenantId { get; set; }
/// <summary>
/// Parent <see cref="OrganizationUnitBase"/>.
/// Null, if this OU is root.
/// </summary>
[ForeignKey("ParentId")]
public virtual TSelf Parent { get; set; }
/// <summary>
/// Parent <see cref="OrganizationUnitBase"/> Id.
/// Null, if this OU is root.
/// </summary>
public virtual long? ParentId { get; set; }
/// <summary>
/// Hierarchical Code of this organization unit.
/// Example: "00001.00042.00005".
/// This is a unique code for a Tenant.
/// It's changeable if OU hierarch is changed.
/// </summary>
[Required]
[StringLength(MaxDisplayNameLength)]
public virtual string Code { get; set; }
/// <summary>
/// Display name of this role.
/// </summary>
[Required]
[StringLength(MaxDisplayNameLength)]
public virtual string DisplayName { get; set; }
/// <summary>
/// Children of this OU.
/// </summary>
public virtual ICollection<TSelf> Children { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="OrganizationUnitBase"/> class.
/// </summary>
public OrganizationUnitBase()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OrganizationUnitBase"/> class.
/// </summary>
/// <param name="tenantId">Tenant's Id or null for host.</param>
/// <param name="displayName">Display name.</param>
/// <param name="parentId">Parent's Id or null if OU is a root.</param>
public OrganizationUnitBase(int? tenantId, string displayName, long? parentId = null)
{
TenantId = tenantId;
DisplayName = displayName;
ParentId = parentId;
}
/// <summary>
/// Creates code for given numbers.
/// Example: if numbers are 4,2 then returns "00004.00002";
/// </summary>
/// <param name="numbers">Numbers</param>
public static string CreateCode(params int[] numbers)
{
if (numbers.IsNullOrEmpty())
{
return null;
}
return numbers.Select(number => number.ToString(new string('0', CodeUnitLength))).JoinAsString(".");
}
/// <summary>
/// Appends a child code to a parent code.
/// Example: if parentCode = "00001", childCode = "00042" then returns "00001.00042".
/// </summary>
/// <param name="parentCode">Parent code. Can be null or empty if parent is a root.</param>
/// <param name="childCode">Child code.</param>
public static string AppendCode(string parentCode, string childCode)
{
if (childCode.IsNullOrEmpty())
{
throw new ArgumentNullException("childCode", "childCode can not be null or empty.");
}
if (parentCode.IsNullOrEmpty())
{
return childCode;
}
return parentCode + "." + childCode;
}
/// <summary>
/// Gets relative code to the parent.
/// Example: if code = "00019.00055.00001" and parentCode = "00019" then returns "00055.00001".
/// </summary>
/// <param name="code">The code.</param>
/// <param name="parentCode">The parent code.</param>
public static string GetRelativeCode(string code, string parentCode)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException("code", "code can not be null or empty.");
}
if (parentCode.IsNullOrEmpty())
{
return code;
}
if (code.Length == parentCode.Length)
{
return null;
}
return code.Substring(parentCode.Length + 1);
}
/// <summary>
/// Calculates next code for given code.
/// Example: if code = "00019.00055.00001" returns "00019.00055.00002".
/// </summary>
/// <param name="code">The code.</param>
public static string CalculateNextCode(string code)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException("code", "code can not be null or empty.");
}
var parentCode = GetParentCode(code);
var lastUnitCode = GetLastUnitCode(code);
return AppendCode(parentCode, CreateCode(Convert.ToInt32(lastUnitCode) + 1));
}
/// <summary>
/// Gets the last unit code.
/// Example: if code = "00019.00055.00001" returns "00001".
/// </summary>
/// <param name="code">The code.</param>
public static string GetLastUnitCode(string code)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException("code", "code can not be null or empty.");
}
var splittedCode = code.Split('.');
return splittedCode[splittedCode.Length - 1];
}
/// <summary>
/// Gets parent code.
/// Example: if code = "00019.00055.00001" returns "00019.00055".
/// </summary>
/// <param name="code">The code.</param>
public static string GetParentCode(string code)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException("code", "code can not be null or empty.");
}
var splittedCode = code.Split('.');
if (splittedCode.Length == 1)
{
return null;
}
return splittedCode.Take(splittedCode.Length - 1).JoinAsString(".");
}
}
We can use it in many entities like ProductCategory, CustomerCategory, UserCategory...
public class ProductOrganization : OrganizationUnitBase<ProductOrganization>
{
public ProductOrganization()
{
}
public ProductOrganization(int? tenantId, string displayName, long? parentId = null)
: base(tenantId, displayName, parentId)
{
}
}
In EF tph or tpt have advantages and disadvantages therefore I dont want to use table hierarchy if I dont have a good reason. For learning purpose could you explain why abstract entities leads framework more complex?
I need to host WebAPI and Dynamic WebAPI controllers in standalone windows form application. Is there any sample or document to do this?
Good starting point... [https://github.com/aspnetboilerplate/aspnetboilerplate/issues/561])
I have an authorization problem with application service. I can successfully get result from application service but if I use AbpAuthorize attribute with the same service it returns unAuthorizedRequest true.
I'm using Content-Type and Authorization (Bearer) headers that explained in [http://www.aspnetboilerplate.com/Pages/Documents/Zero/Startup-Template#token-based-authentication]) document.
Returned json :
{
"success": false,
"result": null,
"error": {
"code": 0,
"message": "No user logged in!",
"details": null,
"validationErrors": null
},
"unAuthorizedRequest": true
}
Meanwhile Tenant/GetTenants service returns the result without any problem but my application service is unauthorized. Edit : Ahh sorry. GetTenants is an anonymous function.
Any advice?
Try data.result instead of data.workTypes in success event.
From AbpAuditLogs...
Abp.Authorization.AbpAuthorizationException: Kullanıcı girişi yapılmamış!
konum: Abp.Authorization.AuthorizeAttributeHelper.<AuthorizeAsync>d__13.MoveNext() D:\Halil\GitHub\aspnetboilerplate\src\Abp\Authorization\AuthorizeAttributeHelper.cs içinde: satır 29
--- Özel durumun oluşturulduğu önceki konumdan başlayan yığın izlemesinin sonu ---
konum: System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
konum: System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
konum: Nito.AsyncEx.AsyncContext.<>c__DisplayClass3.<Run>b__1(Task t)
konum: System.Threading.Tasks.ContinuationTaskFromTask.InnerInvoke()
konum: System.Threading.Tasks.Task.Execute()
--- Özel durumun oluşturulduğu önceki konumdan başlayan yığın izlemesinin sonu ---
konum: System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
konum: System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
konum: Nito.AsyncEx.AsyncContext.Run(Func`1 action)
konum: Abp.Authorization.AuthorizeAttributeHelper.Authorize(IEnumerable`1 authorizeAttributes) D:\Halil\GitHub\aspnetboilerplate\src\Abp\Authorization\AuthorizeAttributeHelper.cs içinde: satır 45
konum: Abp.Authorization.Interceptors.AuthorizationInterceptor.Authorize(IEnumerable`1 authorizeAttributes) D:\Halil\GitHub\aspnetboilerplate\src\Abp\Authorization\Interceptors\AuthorizationInterceptor.cs içinde: satır 86
konum: Abp.Authorization.Interceptors.AuthorizationInterceptor.Intercept(IInvocation invocation) D:\Halil\GitHub\aspnetboilerplate\src\Abp\Authorization\Interceptors\AuthorizationInterceptor.cs içinde: satır 43
konum: Castle.DynamicProxy.AbstractInvocation.Proceed()
konum: Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options) D:\Halil\GitHub\aspnetboilerplate\src\Abp\Domain\Uow\UnitOfWorkInterceptor.cs içinde: satır 53
konum: Abp.Domain.U...
AuthorizeAttributeHelper class throws an exception in AuthorizeAsync method. Line number is 29.
if (!AbpSession.UserId.HasValue)
{
throw new AbpAuthorizationException(LocalizationManager.GetString(AbpConsts.LocalizationSourceName, "CurrentUserDidNotLoginToTheApplication"));
}
AbpSession.UserId has no value! I dont know why...
I think its not possible to use session in self hosted environment...
[http://stackoverflow.com/questions/11347807/httpselfhostserver-and-httpcontext-current])