Contents
Asp.Net Unique Architecture (AUA) Framework
AUA Framework's Overall Structure
ConvertTo and ProjectTo Functions
Calling SQL
Stored Procedure in the AUA Framework
Working with SQL Function in AUA Framework
Working with SQL Views in
the AUA Framework
Message Provider in the AUA framework
Adding Message Provider
to View.csHtml
Displaying messages as HtmlMessages
Displaying messages as DialogMessages
Controlling the Exception Handling Error in the AUA Framework
Schema of Tables in the
AUA Framework
Working with the Setting File in the AUA Framework
Rest WebApi in the AUA Framework
Software projects require constant changes and
updates. If the structure develops in the wrong way, it will prevent changes
and extensions, and most of the time will lead to task duplication or rewriting
of the project from scratch. To get rid of the complexity and task duplication
that most programmers and developers face, which is also caused by the
inconsistency of code at different levels of the program, we need a simple
consistent structure for writing software projects so that we can hide some of
the complexity and focus on business of the task. For example, the Bootstrap
framework is a very useful framework for Front End, but few people would prefer
to use frameworks like Bootstrap for design, and write all of their design with
CSS from the beginning. For the Back End section, however, a simple,
general-purpose framework can save time and cost and produce high-quality code
and a uniform architecture.
This framework allows
developers to develop their projects based on an appropriate integrated
pattern.
The framework must be flexible enough to allow the programmer to apply any
changes needed, relying on its robust structure.
One of the problems of software companies is the lack of the right
structure for developing their projects. As a result, they have often produced
such complex and nested codes that creating changes in one part of the project
severely affects or disrupts other parts. Therefore, lack of the right
structure for development makes it impossible to update the previous code and
reduces the efficiency of the team to almost zero. The reason for this is the
difference in coding and lack of structure and architecture. The development team
must first agree on a set of rules and structures. Architectural patterns are
not the result of a programmer's experiences; they have resulted from the
experiences of hundreds of programmers and design professionals over years.
These frameworks are not innovations or inventions, but are feedbacks on
redesign and recoding that programmers have been involved with in order to
achieve the highest levels of flexibility, extensibility and reusability. Their
use makes the produced codes more simple, flexible and extensible. The use of a
framework can help us save time and cost and make it easier to document and
maintain the system.
AUA is a
simple, lightweight framework for producing projects of any size (small and
large). It can be applied in all architectures (Micro service, CQRS, etc.) due
to its transparency in structure. It is also full of different design patterns,
thus a great source for software architects and developers.
AUA
Framework's Versions:
The different layers of the AUA framework are
as follows:
Layer's Name
|
Use
|
Common Layer
|
This layer contains common items used in other layers,
such as
Enums, Consts,
Extensions,…
،
Tools
|
Data Layer
|
This layer contains items associated with the data
source, including Entity Framework Context, Db Extensions, Search Filters,
Unit of Work Pattern,
Configuration Tools, and Dapper Context
|
Domain Entity
Layer
|
This layer contains the entities and their
configuration. |
Models
Layer
|
This layer contains DTOs, View Models and Config
mapping:
EntitiesDto, ReportModels, View Models ,…
|
Service Infrastructure Layer
|
The overall infrastructure of Services and Repository
is written and becomes ready for use in this layer. |
Service Layer
|
This layer includes all the business services of your
project, including BaseServices, BusinessService, EntitiesService,
ReportService, etc. |
WebApi or Ui Mvc Layer |
This is an interface user layer that can be written
with General MVC- WebApi- GraphQl- Grapc.
|
Test Layer |
This layer is
designed for writing Unit Tests (ToDo)
|
External web service
Layer
|
This layer is for
calling external services. (ToDo)
|
Entity is the main concept, and indeed at the heart of
the architecture of, the AUA framework. Each entity is defined by a class that
contains its features and its relation to other entities. Each entity has an
identifier that can be of any Data Type allowed in .NET, or it can be a
combination of two or more Data Types allowed therein (combination key).
Each entity inherits from the DomainEntity class, to which a primary key field
called Id and one or more monitoring fields (depending on the setting type) are
added.
public class Student
: DomainEntity
{
public string
FirstName {
get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
It should be specified if the primary key has
a data type other than the int data type
(e.g. the Long data type is considered under the primary key)
public class Student : DomainEntity<long>
{
public string
FirstName {
get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
By default the following fields are added to each entity.
The Id key of the primary key and its data type
can be specified when defining an entity.
The IsActive field shows whether the entity is
active or inactive and it has a bool data type.
The RegDate displays the date and time the entity is created
(automatically created inside SQL Server) and does not need to be filled in and
sent.
public class DomainEntity<TPrimaryKey> : BaseDomainEntity<TPrimaryKey>, IAuditInfo
{
public DateTime RegDate { get; set; }
}
public class BaseDomainEntity<TPrimaryKey> : IDomainEntity<TPrimaryKey>
{
public TPrimaryKey Id { get; set; }
public bool
IsActive
{
get; set; }
}
The AUA framework is open-code and can be easily
customized.
Monitoring fields:
You can add more monitoring fields to the entities if you
wish depending on your business.
Monitoring Field Creating the
ICreationAudited
Entity
public interface ICreationAudited
{
long CreatorUserId { get; set; }
}
To add the monitoring field of CreatorUserId,
we can simply implement the ICreationAudited interface
for the DomainEntity class, as follows:
public class DomainEntity<TPrimaryKey> : BaseDomainEntity<TPrimaryKey>, IAuditInfo, ICreationAudited
{
public DateTime RegDate { get; set; }
public long
CreatorUserId {
get; set; }
}
Auditing
fields
of
deleting the
IDeletionAudited
entity
The IDeletionAudited interface can be used to prevent the
physical deletion and add the monitoring fields of entity deletion.
public interface IDeletionAudited: ISoftDelete
{
long? DeleterUserId { get; set; }
DateTime? DeleteDate {
get; set; }
}
public interface ISoftDelete
{
bool IsDeleted { get; set; }
}
Auditing
fields for
editing
IModifiedAudited
The IModifiedAudited interface can be used to add monitoring
fields for editing an entity.
public interface IModifiedAudited
{
long? ModifierUserId { get; set; }
DateTime? ModifyDate {
get; set; }
}
Configuration of entities:
There is a configuration class for each entity
that can specify the length of field settings for it.
public class StudentConfig
:
IEntityTypeConfiguration<
Student>
{
public void
Configure(
EntityTypeBuilder<Student> builder)
{
builder
.Property(p => p.FirstName)
.HasMaxLength(
LengthConsts.MaxStringLen50);
builder
.Property(p => p.LastName)
.HasMaxLength(
LengthConsts.MaxStringLen50);
}
}
We configure the entity with the combination key as
follows. The AppUserId and RoleId fields are both
Keys to the UserRole entity
We configure the entity with the combination key as
follows. The AppUserId and RoleId fields are both keys to the UserRole entity
public class UserRoleConfig : IEntityTypeConfiguration<UserRole>
{
public void
Configure(EntityTypeBuilder<
UserRole> builder)
{
builder.Ignore(p => p.Id);
builder
.HasKey(p =>
new { p.AppUserId, p.RoleId });
}
{
Models and Mapping:
Models inherit the
BaseEntityDto
class at AUA, and the monitoring and Id fields are added automatically
to them. The AUA framework has two mapping methods of
IMapFrom
and IHaveCustomMappings to map one
object to another. In the IMapFrom model,
only fields with the same name are mapped, and there is no mapping for those
with different names. This type of mapping is the simplest and fastest type of
mapping. In the example below, a Student entity is mapped to a StudentDto, as follows:
public class StudentDto : BaseEntityDto, IMapFrom<Student>
{
[Display(Name =
"First Name ")]
public string
FirstName {
get; set; }
[Display(Name =
"Last Name")]
public string
LastName
{
get; set; }
[Display(Name =
"Age")]
public int Age { get; set; }
public string FullName => $"{FirstName} {LastName}";
}
IHaveCustomMappings Method
In the
IHaveCustomMappings
model, not only fields with the same name, but also each field of the
source model can be mapped to the Linq commands. In this case, your map
includes configuration, which is performed at the bottom of the model. This
method is very flexible. Anything that can be written with the Linq commands
for an entity can be written with this type of mapping. Below is a mapping
example that maps an object from AppUser to AppUserDto. In addition, access levels and roles
are mapped. In the reporting section, we will use complex mapping for
reporting.
public class AppUserDto: BaseEntityDto<long>, IHaveCustomMappings
{
public string
FirstName {
get; set; }
public string
LastName
{
get; set; }
public string
UserName
{
get; set; }
public string
FullName
=> FirstName +
" " + LastName;
public string
Password
{
get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public bool
IsActive
{
get; set; }
public virtual
ICollection<UserRole> UserRoles {
get; set; }
public void
ConfigureMapping(Profile configuration)
{
configuration.CreateMap<
AppUser, AppUserDto>()
.ForMember(p => p.UserRoles, p =>
p.MapFrom(q => q.UserRoles))
.ReverseMap();
}
}
To help with mapping operations, you can convert
an object or list of objects into one or a list of view models without any
restrictions, and use IMapFrom and IHaveCustomMappings to configure mapping
operations (MapperInstance is by default an instance of AutoMapper in all
services). For example, we have created a view model called TestMappingVm that
uses IHaveCustomMappings to configure mapping operations, thereby mapping a
query of the AppUser entity to this view model using
ConvertTo
and ProjectTo.
public class TestMappingVm : IHaveCustomMappings
{
public string
Email {
get; set; }
public string
PersonName {
get; set; }
public int
RoleCount {
get; set; }
public ICollection<Role> UserRoles { get; set; }
public void
ConfigureMapping(Profile
configuration)
{
configuration.CreateMap<
AppUser, TestMappingVm>()
.ForMember(p =>
p.PersonName, p => p.MapFrom(q => q.FirstName +
" " + q.LastName))
.ForMember(p => p.RoleCount,
p => p.MapFrom(q => q.UserRoles.Count))
.ForMember(p => p.UserRoles,
p => p.MapFrom(q => q.UserRoles.Select(m => m.Role)))
.ReverseMap();
}
}
Mapping using ProjectTo:
public IEnumerable<TestMappingVm> GeTestMappingVms()
{
var
query = GetAll().Where(p => p.IsActive);
return
MapperInstance
.
ProjectTo<TestMappingVm>(query)
.ToList();
}
Mapping
using ConvertTo
public IEnumerable<TestMappingVm> GeTestMappingVms()
{
var
query = GetAll().Where(p => p.IsActive);
return query
.
ConvertTo<TestMappingVm>(MapperInstance)
.ToList();
}
One of the most important features of the AUA
framework is its high security. Security and performance have always been in
conflict. The Heilton security team has worked hard to design a very secure way
to raise security while maintaining the performance and has used it in the AUA
framework.
Each view model and DTO inherit from the
generic class BaseEncryptionVm <TPrimaryKey>, and two
EncKeyId
and DecKeyId fields are added to it.
EncKeyId
is the encrypted equivalent of the primary key (Id). The encryption key is
generated for each different user. If the programmer specifies this field in
its Select command, it will produce its framework; otherwise, it will not
produce it.
DecKeyId is equivalent to Id.
In addition, the DecKeyId function has been
considered in the BaseController. It
receives EncKeyId and converts it to Id, and
the programmer is not involved in encryption and hash algorithms under any
circumstances (however, this feature can be avoided and that id may be used
instead).
public async Task<IActionResult> _Update(string keyId)
{
var
userId =
DecKeyId
<
long
>(keyId);
var model = await
_appUserService.GetAppUserVmAsync(userId);
return View(model);
}
All business is implemented in the form of
services and created in the service layer. The service layer uses the Service Infrastructure
layer and automatically connects to each service in its own Repository. The
advantage of this approach is that the developer is not involved in the two
concepts of repository and service and focuses only on the service itself. The
service has its own built-in Repository, which is one of the most important
features of the AUA framework architecture. For example, if we want to write a
service for Student Entity, we must first create an interface for Student
Entity which inherits from the
IGenericEntityService
class.
public interface IStudentService : IGenericEntityService<Student, StudentDto>
{
}
After Interface
you can create the desired service. The service must inherit from the GenericEntityService class and implement the IStudentService interface built in the previous
step.
public class StudentService: GenericEntityService<Student,StudentDto>,IStudentService
{
public StudentService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}
By default, the service created contains all
the functions required to work with Repository.
List of Repository functions that are
automatically added to each service.
.
Function
|
Description
|
GetAll
|
This returns all entities and can be
filtered. It also supports Async. |
GetAllDto
|
This returns all entities in DTO format and can
be filtered. It also supports Async. |
GetCount
|
Number of entities - can be filtered.
|
GetFirst
|
This returns the first entity and can be
filtered. |
GetLast
|
This returns the last entity and can be
filtered. |
GetCountAsync
|
Number of entities – filterable; supporting Async
|
GetFirstAsync
|
This returns the first entity and can be
filtered; supporting Async |
GetLastAsync |
This returns the last entity and can be
filtered; supporting Async |
GetDtoById |
Holding entity and mapping it in DTO format
|
GetByIdAsync |
Holding entity with the primary key;
supporting Async |
GetDtoByIdAsync |
Holding entity and mapping it in DTO format; supporting
Async
|
Delete |
Deleting entity with the primary key or DTO
|
DeleteAsync |
Deleting entity with the primary key or DTO; supporting
Async
|
Insert |
Inserting new entity with Entity or DTO
|
InsertAsync |
Inserting new entity; supporting Async
|
InsertMany |
Inserting multiple entities simultaneously |
InsertManyAsync |
Inserting multiple entities simultaneously; supporting Async
|
InsertCustomVm |
Inserting entity with custom view model (when part of
entity fields is sent from view)
|
InsertCustomVmAsync |
Inserting entity with custom view model
; supporting
Async
|
PartialInsert |
Inserting entity into repository without sending to
database; supporting Async
|
Update |
Editing new entity with Entity or DTO
|
UpdateAsync |
Editing new entity with Entity or DTO
; supporting
Async
|
UpdateCustomVm |
Editing entity with custom view model (when part of
entity fields is sent from view)
|
UpdateCustomVmAsync |
Editing entity with custom view model (when part of
entity fields is sent from view)
|
PartialUpdate |
Inserting entity into repository without sending to
database; supporting Async
|
ConvertTo |
This converts a query result to another object based on
configuration mapping
|
ProjectTo |
This projects a query result to another object based on
configuration mapping
|
SaveChange |
This specifies the final status when using Partial
Functions.
|
SaveChangeAsync |
This specifies the final status when using Partial
Functions; supporting Async
|
The developer can
implement his business into the services. One service can use other
services.
You can easily inject services into another and use it.
In the AUA framework, you as administrator can
control the users' access to the smallest possible level. This is done by the
user management module. You can assign roles to users by defining them and
assigning User Access levels to them. The diagram below shows the levels of
access to the AUA Word Framework.
.
There are four models of Authentication and Authorization
in the AUA framework and it is possible to specify the level of access in the
controller and action.
1. WebAuthorize: This
attribute allows you to specify access levels for the action and controller.
2. AllowLoggedInUser:
The user has just to log in.
3. OnlyLocalActionAuthorize: This attribute is for
actions and controllers that only need to be called locally on the server.
4. AllowAnonymousAuthorize: Any user can have
unlimited access to this action and controller
To use WebAuthorize,
you must add an item for each control or action in EUserAccess.
In the database in the UserAccess table we add the name, access number,
description and URL.
public enum EUserAccess
{
#region Accounting
[
Description("
User
Management
")]
AppUser = 1,
[
Description("
Access
level management
")]
UserAccess = 2,
[
Description("
Role
management
")]
UserRole = 3,
[
Description("
Role-level
access management
")]
UserRoleAccess = 4,
#endregion
}
To use WebAuthorize,
you need to write it for the controller or action. For example, the following
action is accessible only for users who have access to AppUser = 1.
[
WebAuthorize
(
EUserAccess
.
AppUser
)]
public async Task<IActionResult
> _Insert(AppUserDto appUserDto)
{
await _appUserService.InsertAsync(appUserDto);
return RedirectToAction("Index");
}
WebAuthorize
input can have several levels of access. That is, the user has access to
that resource if he has access to one of these.
The page title is loaded by default according to the
description in the UserAccess table for the
page.
One of the most important features of software is
reporting with different capabilities and one of the concerns of programmers is
the addition and modification of filters which is performed in the AUA
framework easily and at a high speed and you can create your own report with
various filters. To create a report, we first make a view model to apply
filters and another view model to display the output and finally write our
search filter to apply the filters.
For example, we create a report of all users and all
their access.
View Model of Search Filter:
public class
UserAccessReportSearchVm
:
BaseSearchVm
{
public string
FirstName {
get; set; }
public string
LastName
{
get; set; }
public string
UserName
{
get; set; }
public bool
?
IsActive {
get; set; }
public List<SelectListItem> RecordStatusItem { get; set; }
public string
RoleTitle {
get; set; }
public string
UserAccessTitle {
get; set; }
}
View Model of Report output:
public class UserAccessReportGridVm : BaseEntityDto<long>, IHaveCustomMappings
{
public string
FirstName {
get; set; }
public string
LastName
{
get; set; }
public string
UserName
{
get; set; }
public string
RoleTitle {
get; set; }
public string
FullName
=> FirstName +
" " + LastName;
public string
Password
{
get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
public ICollection<Role> UserRoles { get; set; }
public IEnumerable<UserAccess> UserAccess { get; set; }
public string
UserRolesTitles =>
string.Join("<br/> "
, UserRoles.Select(p
=> p.Title));
public string
UserAccessTitles =>
string.Join("<br/> "
,
UserAccess.Select(p => p.Title));
public void
ConfigureMapping(Profile configuration)
{
configuration.CreateMap<AppUser,
UserAccessReportGridVm>()
.ForMember(p => p.UserRoles,
p => p.MapFrom(q => q.UserRoles.Select(r => r.Role)))
.ForMember(p =>
p.UserAccess, p => p.MapFrom(q => q.UserRoles.SelectMany(t =>
t.Role.UserRoleAccess.Select(m =>
m.UserAccess))))
.ReverseMap();
}
}
After creating the search view and grid view of the
model, we write a search filter to apply the filters.
public class UserAccessReportFilter : Specification<AppUser>
{
private readonly UserAccessReportSearchVm _searchVm;
private Expression<Func<AppUser, bool>> _expression = p => true;
protected bool
IsEmptyFilter => _searchVm ==
null;
public UserAccessReportFilter(UserAccessReportSearchVm searchVm)
{
_searchVm = searchVm;
}
public override Expression<Func<AppUser, bool>> IsSatisfiedBy()
{
if (IsEmptyFilter) return p => true;
ApplyDefaultFilter();
ApplyFirstNameFilter();
ApplyLastNameFilter();
ApplyUserNameFilter();
ApplyIsActiveFilter();
ApplyRoleTitleFilter();
ApplyUserAccessTitleFilter();
return _expression;
}
private void ApplyDefaultFilter()
{
}
private void
ApplyFirstNameFilter()
{
if (string.IsNullOrWhiteSpace(_searchVm.FirstName))
return;
_expression = _expression.And(p
=>
p.FirstName.Contains(_searchVm.FirstName));
}
private void ApplyLastNameFilter()
{
if (string
.IsNullOrWhiteSpace(_searchVm.LastName))
return;
_expression = _expression.And(p
=> p.LastName.Contains(_searchVm.LastName));
}
private void ApplyUserNameFilter()
{
if (string
.IsNullOrWhiteSpace(_searchVm.UserName))
return;
_expression = _expression.And(p
=> p.UserName.Contains(_searchVm.UserName));
}
private void ApplyIsActiveFilter()
{
if (_searchVm.IsActive == null)
return;
_expression = _expression.And(p
=> p.IsActive == _searchVm.IsActive);
}
private void
ApplyRoleTitleFilter()
{
if (string
.IsNullOrWhiteSpace(_searchVm.RoleTitle))
return;
_expression =
_expression.And(p => p.UserRoles.Any(r =>
r.Role.Title.Contains(_searchVm.RoleTitle)));
}
private void
ApplyUserAccessTitleFilter()
{
if (string
.IsNullOrWhiteSpace(_searchVm.UserAccessTitle))
return;
_
expression
= _expression.And(p => p.UserRoles.Any(r =>
r.Role.UserRoleAccess.Any(a =>
a.UserAccess.Title.Contains(_searchVm.UserAccessTitle))));
}
The output of this report can be viewed as
follows.
Calling SQL Stored Procedure in the
AUA Framework
Most of the time, the programmer resorts to
other ways like Ado.net and Dapper to easily work with the
SQL Stored
Procedure
, not knowing that he can simply manage the number of
connections made or create a separate context for it. SQL Stored Procedure is
called easily in the AUA Framework and has none of the above problems.
Example: Procedure call that gives the list of
a user's access in the AUA framework is as follows:
CREATE PROCEDURE [dbo].[uspGetUserRoles]
@userId bigint
AS
SELECT ROLE.Id as RoleId,ROLE.Title,ROLE.Description
FROM UserRole INNER JOIN ROLE
ON UserRole.RoleId=ROLE.Id
WHERE UserRole.AppUserId=@userId
We create a view model for the output of the
procedure.
public class GetUserRolesSpResult
{
public int
RoleId {
get; set; }
public string Title { get; set; }
public string
Description {
get; set; }
}
To call a procedure in StoredProcContext
, we add the
following code.
public
IQueryable<GetUserRolesSpResult>
GetUserRolesSp(long userId)
{
var cmd = LoadStoredProc(StoredProcedureConsts.
GetUserRoles
)
.WithSqlParam(
"userId", userId);
return cmd
.ExecuteStoredProc<GetUserRolesSpResult>();
}
To avoid the dispersal of the procedures' names, we place them in the class
in a fixed order.
public class StoredProcedureConsts
{
public const string GetAppUsersCount = "uspGetAppUsersCount"
;
public const string GetUserRoles = "uspGetUserRoles";
}
The framework allows you to query the output
of the procedure, but this is not correct, as it should write its own procedure
for each task. The
StoredProcService
service, which includes all procedures, allows you to call your own
processor.
public class StoredProcService : FuncBaseService, IStoredProcService
{
public StoredProcService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
public IQueryable<GetUserRolesSpResult> GetUserRolesSp(long userId)
{
return UnitOfWork
.StoredProc
.GetUserRolesSp(userId);
}
}
Working with SQL Function in AUA Framework
One of
the good features of the AUA framework is that it works with functions in the
SQL Server to map their result to objects, and to write a LINQ query on their
results, which can easily be done in AUA frameworks and it avoids generating a
dirty code for this task.
For example: We call with the AUA framework a
function that takes the user code and returns its name.
CREATE FUNCTION
[dbo]
.[GetUserName] (@userId BIGINT)
RETURNS NVARCHAR(200) AS
BEGIN
RETURN (SELECT UserName FROM AppUser WHERE Id=@userId)
END
In SqlFunctionContext,
you can add a new function call.
public class SqlFunctionContext
{
private readonly DbContext _dbContext;
public SqlFunctionContext(DbContext dbContext)
{
_dbContext = dbContext;
}
public string
GetUserName(
long userId)
{
var resultParameter = new SqlParameter("@result", SqlDbType.NVarChar, 200)
{
Direction = ParameterDirection.Output
};
ExecuteSqlCommand(
$"SET @result=
dbo.GetUserName('
{userId}')",resultParameter);
return resultParameter.Value as string;
}
private void
ExecuteSqlCommand(
string
sqlCommand, IDbDataParameter resultParameter)
{
_dbContext?
.Database?
.ExecuteSqlCommand(sqlCommand,
resultParameter);
}
}
In the SqlFunctionService service, the function can be
accessed and called.
.
public class SqlFunctionService : FuncBaseService, ISqlFunctionService
{
public SqlFunctionService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
public string
GetUserName(
long userId)
{
return UnitOfWork
.SqlFunction
.GetUserName(userId);
}
}
One of the concerns of .NET programmers is working with
SQL Views so that they can map their results in objects and apply filters on
the outputs of the view. The Entity Framework recognizes the views as a table, but
the AUA framework makes it possible to map the view output to the objects and
apply a filter to it.
CREATE VIEW [dbo].[UserRolesVw] AS
SELECT AppUser.Id AS userId,AppUser.UserName,Role.Title
FROM AppUser INNER JOIN UserRole
ON AppUser.Id=UserRole.AppUserId
INNER JOIN Role
ON UserRole.RoleId=Role.Id
GO
For the view output, we write a class that
inherits from BaseView.
public class UserRolesVw : BaseView
{
public long
UserId {
get; set; }
public string
UserName
{
get; set; }
public string Title { get; set; }
}
We also make a View DTO for the View output (if we want to create a change
in the View output, we apply it to the DTO).
public class UserRolesVwDto : IMapFrom<UserRolesVw>
{
public long UserId { get; set; }
public string
UserName
{
get; set; }
public string Title { get; set; }
}
We also create a service to work with the view, where
filters will be written for the view.
Interface:
public interface IUserRolesVwService : IBaseGenericService<UserRolesVw, UserRolesVwDto>
{
}
View Service:
public class UserRolesVwService
:
BaseGenericService<
UserRolesVw, UserRolesVwDto>, IUserRolesVwService
{
public UserRolesVwService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}
Functions that are added to the view service by default are as follows:
GetAll
|
This returns all entities and can be
filtered. It also supports Async. |
GetAllDto
|
This returns all entities in DTO format and
can be filtered. It also supports Async. |
GetCount
|
Number of entities - can be filtered.
|
GetFirst
|
This returns the first entity and can be
filtered. |
GetLast
|
This returns the last entity and can be
filtered. |
GetCountAsync
|
Number of entities – filterable; supporting Async
|
GetFirstAsync
|
This returns the first entity and can be
filtered; supporting Async |
GetLastAsync |
This returns the last entity and can be
filtered; supporting Async |
GetDtoById |
Holding entity and mapping it in DTO format
|
GetByIdAsync |
Holding entity with the primary key;
supporting Async |
GetDtoByIdAsync |
Holding entity and mapping it in DTO format; supporting
Async
|
ConvertTo |
This converts a query result to another object based on
configuration mapping
|
ProjectTo |
This projects a query result to another object based on
configuration mapping
|
The AUA framework contains two types of Message Box,
namely Html Messagebox and Dialog Messagebox.
If we use HtmlMessages in View.csHtml, messages will be
displayed in Html in the right color, if we use DialogMessages, they will be
displayed in dialog, and if both models are loaded in the view, they will be
displayed as Html and dialog.
Messagebox Types:
NotifyMessage
SuccessMessage
ErrorMessage
WarningMessage
Message
<div class="form-group">
<
partial
name
="MessageProvider/HtmlMessages/_AllHtmlMessage" />
</div>
@* OR *@
<div class="form-group">
<
partial
name
="MessageProvider/DialogMessages/_AllDialogMessage" />
</div>
In the controller, we can easily send the message to the
view and display it.
public IActionResult Index()
{
NotifyMessage("** NotifyMessage **");
SuccessMessage("** SuccessMessage **");
ErrorMessage("** ErrorMessage **");
WarningMessage(
"**
WarningMessage **"
);
Message(
"** Message **");
return View();
}
Displaying messages as HtmlMessages
One of the most important modules of the AUA framework
is its error control module. This framework is perfect at error control and
management. For example: When a user enters one of the actions, an expression
occurs but the error page does is not displayed and the error text is displayed
as a controlled message and the URL does not change.
Anywhere we want to interrupt request
processing a request, we can throw an Exception and interrupt the process, in
which case the error is sent to the error control module.
For example: If the user is not logged in, the
request processing should be stopped and an error will be displayed.
public IActionResult Index()
{
if (CurrentUser is null)
throw new ClientException("Custom Error Exception"
);
{
public
IActionResult Index()
{
if (CurrentUser is null
)
throw new ClientException("Custom Error Exception");
{
Error management module and displaying it as a
message
One of the security issues in SQL Server is the schema of tables. By
default, the names of tables are stored with the dbo prefix in the SQL Server.
It is easily possible to customize this schema in the AUA framework.
To manage and prevent the dispersal of constants in the program, we write
them in the classes in a fixed order.
public class SchemaConsts
{
public const string Accounting = "Acc";
public const string School = "Sch";
}
[
Table
(
"Student"
, Schema =
SchemaConsts
.
School
)]
public class Student : DomainEntity
{
public string
FirstName {
get; set; }
public string
LastName
{
get; set; }
public int Age { get; set; }
}
Results of schema application in database
Working with the Setting File in the AUA Framework
One of the dirty codes
found in most projects is how to read values from files like AppSetting.json,
WebConfig, and setting files in ASp.net Core, which in most cases causes
errors. In the AUA framework with appropriate design patterns, we read these
files in Json, Xml. There are two types of setting files in Json and Xml
formats (Setting.xml, and appsettings.json).
The following code uses
the appsettings.json file to read the value of the encryption key
public class AppSetting
{
public static string
GetDataEncryptionKey =>
AppConfiguration
.GetConfigurationRoot()
.GetSection(AppSettingConsts.AppSetting)
.GetSection(AppSettingConsts.DataEncryptionKey)
.Value;
}
To read the value of the encryption key from the
configuration file:
Var dataEncryptionKey= AppSetting.GetDataEncryptionKey
To work with the XML setting file, we have
used the Xml Pattern
https://github.com/Heilton/XmlPattern
Rest WebApi in the AUA Framework
API is a software implementation
interface that allows other applications to interact with it. It enables us to
implement HTTP protocol-based services more easily than ever. Many service
receivers, such as web browsers, mobile devices, and desktop applications, can
take advantage of the capabilities of this platform (Web Api).
In the last layer of the
AUA framework, we can use different technologies such as the MVC - Rest WebApi-Grpc-
Graphql. JWT (Json web Token) technology can
be implemented and used for WebApi access levels in the AUA framework.
Swagger is used for ease
of use and WebApi testing. All the requirements for login and access levels using
Token for the AUA framework are written in WebApi version and are ready for
your business development.
Note that the AUA
framework can also be used for Windows form application, WPF, etc., because the
last layer changes. The AUA framework is beyond the scope of this document.
This document is just aimed at familiarizing you with how to work with the AUA
framework. Using this document and tutorial videos, the programmer, regardless
of his/her level, can work with this framework within just a week.
The AUA framework has
tutorial videos for all stages and can be easily worked with. You can download
the tutorial video on how to work with the AUA framework from the Hilton
website at
www.heilton.com
or www.youtube.com .
WebSite | Phone | |
---|---|---|
AUA_Framework@yahoo.com mr_Lotfi@ymail.com |
www.Heilton.com | +98-9199906342 |