{"id":20165586,"url":"https://github.com/nigje/davli","last_synced_at":"2025-03-03T03:24:05.786Z","repository":{"id":116577624,"uuid":"396858984","full_name":"Nigje/Davli","owner":"Nigje","description":"Davli is a framework based on ASP.Net Core for web projects with requirements such as high-performance, scalability, reliability, extensibility.","archived":false,"fork":false,"pushed_at":"2021-08-29T17:02:07.000Z","size":51,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-13T14:52:38.727Z","etag":null,"topics":["aspnetcore","autofac","efcore","minio","sqlserver","swagger"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nigje.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-16T15:39:31.000Z","updated_at":"2024-02-14T16:01:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"fb59d97a-472e-4d7a-81bb-b305eac8f57f","html_url":"https://github.com/Nigje/Davli","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nigje%2FDavli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nigje%2FDavli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nigje%2FDavli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nigje%2FDavli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nigje","download_url":"https://codeload.github.com/Nigje/Davli/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241601595,"owners_count":19988921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","autofac","efcore","minio","sqlserver","swagger"],"created_at":"2024-11-14T00:38:23.872Z","updated_at":"2025-03-03T03:24:05.773Z","avatar_url":"https://github.com/Nigje.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Davli \n\nDavli is a framework based on ASP.Net Core for web projects with requirements such as high-performance, scalability, reliability, extensibility. Davli uses the update and famous technologies in ASP.Net Core. Davli is the summary of different frameworks. The following is a list of technologies that are used in Davli. I'm going to regularly update the document in the next commits.\n\n### Technologies:\n\n- .Net5\n- EF Core\n- Autofac\n- Swagger\n- MinIO\n- SQL Server\n\n\n\n### Todo:\n\n- Standard Repository Implementation example.\n\n- Minio documentation.\n\n- Settings documentation.\n\n- Filter documentation.\n\n- Add Automapper.\n\n- Add Docker and cocker-compose.yml.\n\n- Add Serilog, Elasticsearch, Kibana, Fluentd, Nginx.\n\n  \n\n## Integrate with a project\n\nDavli is designed for ASP.Net Web API applications and there is a sample project that you can debug Davli. To integrate it with your project you should do some changes in `Program.cs` and `Sturtup.cs`. At the first step, you should register `AutofacServiceProviderFactory` by using it as the following in the `Program.cs` file to integrate `Autofac` with project. \n\n```c#\npublic static IHostBuilder CreateHostBuilder(string[] args) =\u003e\n            Host.CreateDefaultBuilder(args)\n             .UseServiceProviderFactory(new AutofacServiceProviderFactory())\n                .ConfigureWebHostDefaults(webBuilder =\u003e\n                {\n                    webBuilder.UseStartup\u003cStartup\u003e();\n                });\n```\n\nAfter that, add the following function to Sturtup.cs to define dependency injection roles. In Autofac section we will explain details.\n\n```C#\npublic void ConfigureContainer(ContainerBuilder builder)\n        {\n            builder.RegisterModule(new DIModule());\n            builder.RegisterModule(new DavliDIModule());\n        }\n```\n\nAt the second step, register Davli's services by `AddDavliServices` in `ConfigureServices` function at `Sturtup.cs` file.\n\n```c#\nservices.AddDavliServices(Configuration);\n```\n\nAlso, to use SQL SERVER database add the following code to `ConfigureServices`  function after registering Davli's services. `SampleApiDbContext` is your `DbContext` and you will define your poco models there. In the EF Core section, I will explain more details.\n\n```C#\nservices.AddDbContext\u003cDavliDBContext, SampleApiDbContext\u003e(opt =\u003e opt.UseSqlServer(Configuration.GetConnectionString(\"Davli\")),\n                ServiceLifetime.Transient);\n```\n\nYour ConfigureServices will lookl like the following code.\n\n```C#\npublic void ConfigureServices(IServiceCollection services)\n        {\n            services.AddDavliServices(Configuration);\n            services.AddDbContext\u003cDavliDBContext, SampleApiDbContext\u003e(opt =\u003e opt.UseSqlServer(Configuration.GetConnectionString(\"Davli\")),\n                ServiceLifetime.Transient); \n        }\n```\n\nFinally, add UseDavliApplication to your Configure function in Startup.cs file. your Configure function will look like the following code:\n\n```c#\npublic void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n    {\n        app.UseDavliApplication();\n\n        app.UseRouting();\n        app.UseEndpoints(endpoints =\u003e\n        {\n            endpoints.MapControllers();\n        });\n    }\n```\n\n\n\n## EF Core\n\n[Entity Framework (EF)](https://docs.microsoft.com/en-us/ef/core/) Core is a lightweight, extensible, [open source](https://github.com/dotnet/efcore) and cross-platform version of the popular Entity Framework data access technology. \n\nI used it in combination with a generic repository pattern and without it (I will explain their details in the generic repository pattern section and the standard repository section). To use it, add the following code to your `ConfigureServices` function in `Startup.cs`. `SampleApiDbContext` is your `DbContext` and you should define your poco models there.\n\n```C#\npublic void ConfigureServices(IServiceCollection services)\n        {\n            services.AddDavliServices(Configuration);\n            services.AddDbContext\u003cDavliDBContext, SampleApiDbContext\u003e(opt =\u003e opt.UseSqlServer(Configuration.GetConnectionString(\"Davli\")),ServiceLifetime.Transient); \n        }\n```\n\n\n\nThe following code is implementation of  `SampleApiDbContext` that has a User object (User is a poco object).\n\n```c#\npublic class SampleApiDbContext: DavliDBContext\n{\n    public SampleApiDbContext(DbContextOptions\u003cSampleApiDbContext\u003e options, RequestContext requestContext) : base(options, requestContext)\n    {\n        RequestContext = requestContext;\n    }\n    public DbSet\u003cUser\u003e Users { get; set; }\n}\n```\n\n\n\nsAlso, to use the generic repository, all poco models should derive the `DavliEntity\u003cTPrimaryKey\u003e` class. `DavliEntity\u003cTPrimaryKey\u003e` gets a type as the primary key and the implementation of it is as follows. All properties in `DavliEntity\u003cTPrimaryKey\u003e` automatically update by Davli. For more details and soft delete check the `DavliDBContext` class\n\n```c#\npublic class DavliEntity\u003cTPrimaryKey\u003e : IDavliEntity, ICreationConcept, IModificationConcept\n    {\n        public TPrimaryKey Id { get; set; } //Primary key\n        public DateTime? LastModificationTime { get; set; } //Indicates the last time the change was applied\n        public long? LastModifierUserId { get; set; } //Indicates who was the last person to change the data \n        public DateTime CreationTime { get; set; } //Indicates the time the entity was created\n        public long? CreatorUserId { get; set; } //Indicates who created the data\n    }\n```\n\nThe implementation of the User class is as follows. The type of its primary key is `long` and its name is `Id`.\n\n```c#\npublic class User : DavliEntity\u003clong\u003e\n    {\n        [MaxLength(100)]\n        public string Name { get; set; }\n    }\n```\n\n\n\n#### Generic Repository Pattern\n\nYou can debug this section by calling `UserController` actions. Also, the `UserService` class implementation is based on the generic repository pattern. After implementation of poco models, to use the generic repository pattern you need to inject `IUnitOfWork` in your class and manipulate your entities by `_unitOfWork.GenericRepository\u003cDavliEntity\u003cTPrimaryKey\u003e\u003e()` and its methods. `GenericRepository\u003cDavliEntity\u003cTPrimaryKey\u003e\u003e()` returns `IRepository\u003cDavliEntity\u003cTPrimaryKey\u003e\u003e` and it has common Linq .Expression methods. For more information about it check `Repository.cs` class (to prevent access to data query from business layer replace `IQueryable` by `Enumerable` in `Where` function).  To save changes use `_unitOfWork.SaveAsync()`. A simple example of it is as follows.\n\n```c#\npublic class UserService : IUserService, ITransientLifetime\n{\n    private readonly IUnitOfWork _unitOfWork;\n    \n\tpublic UserService(IUnitOfWork unitOfWork)\n\t{\n\t\t_unitOfWork = unitOfWork;\n\t}\n\n\tpublic async Task\u003cUserModel\u003e AddNewUserAsync(RegisterUserModel registerUserModel)\n\t{\n\t\tUser user = new User { Name = registerUserModel.Name };\n\t\t_unitOfWork.GenericRepository\u003cUser\u003e().Add(user);\n\t\tawait _unitOfWork.SaveAsync();\n\t\treturn new UserModel { Id = user.Id, Name = user.Name };\n\t}\n    \n    public async Task DeleteUserAsync(long userId)\n\t{\n\t\tUser user = await _unitOfWork.GenericRepository\u003cUser\u003e().FirstOrDefaultAsync(x =\u003e x.Id == userId);\n\t\tif (user == null)\n\t\t\tthrow new DavliExceptionNotFound(\"User not found.\");\n\t\tawait _unitOfWork.GenericRepository\u003cUser\u003e().RemoveAsync(x =\u003e x.Id == userId);\n\t\tawait _unitOfWork.SaveAsync();\n\t}\n}\n```\n\n\n\n#### Standard Repository Implementation\n\n//Todo: Implement a sample.\n\n\n\n## Migrations\n\nTo add new models use the following code in command line.\n\n```powershell\ndotnet ef migrations add InitialModels --project Davli.Framework.SampleApi\n```\n\nif you got a error like the following message, update your EF tools by `dotnet tool update --global dotnet-ef`\n\n\u003e The Entity Framework tools version 'x.x.x' is older than that of the runtime 'y.y.y'. Update the tools for the latest features and bug fixes.\n\u003e The name 'InitialModels' is used by an existing migration.\n\n```powershell\ndotnet tool update --global dotnet-ef\n```\n\nTo update database use the following code.\n\n```powershell\ndotnet ef database update --project Davli.Framework.SampleApi\n```\n\n\n\n## Swagger\n\n[Swagger](https://swagger.io/tools/swagger-ui/) is an Interface Description Language for describing RESTful APIs expressed using JSON. Swagger UI allows anyone — be it your development team or your end consumers — to visualize and interact with the API’s resources without having any of the implementation logic in place. It’s automatically generated from your OpenAPI (formerly known as Swagger) Specification, with the visual documentation making it easy for back end implementation and client side consumption. Swagger UI is embedded in Davli and just needs to add the following config to `appsetting.json`. To access Swagger UI use `{hostname}/swagger` address (you can change default `launchUrl` at your project `Properties/launchSettings.json` file).  \n\n```json\n{\n  \"SwaggerOption\": {\n    \"JsonRoute\": \"swagger/{documentName}/swagger.json\",\n    \"Description\": \"Sample Api\",\n    \"Name\": \"nameofApi\",\n    \"UIEndpoint\": \"v1/swagger.json\",\n    \"Title\": \"Title of Api\",\n    \"Version\": \"Version of Api\"\n  }\n}\n```\n\n\n\n## Autofac\n\n[Autofac](https://autofac.org/) is an addictive [Inversion of Control container](http://martinfowler.com/articles/injection.html) for .NET Core, ASP.NET Core. It manages the dependencies between classes so that **applications stay easy to change as they grow** in size and complexity. To integrate it with your project you should do some changes in `Program.cs` and `Sturtup.cs`. At the first step, you should register `AutofacServiceProviderFactory` by using it as the following in the `Program.cs` file to integrate `Autofac` with project. \n\n```c#\npublic static IHostBuilder CreateHostBuilder(string[] args) =\u003e\n            Host.CreateDefaultBuilder(args)\n             .UseServiceProviderFactory(new AutofacServiceProviderFactory())\n                .ConfigureWebHostDefaults(webBuilder =\u003e\n                {\n                    webBuilder.UseStartup\u003cStartup\u003e();\n                });\n```\n\nAfter that, add the following function to `Startup.cs` to define dependency injection roles. To register Davli class you have to register `DavliDIModule` and for the current project (for example `Sample.Api`) you have to register `DIModule`.  `DIModule` and `DavliDIModule` have the same content that you can change and use just one of them.\n\n```C#\npublic void ConfigureContainer(ContainerBuilder builder)\n        {\n            builder.RegisterModule(new DIModule());\n            builder.RegisterModule(new DavliDIModule());\n        }\n```\n\nResolving services has the following life times and for each of them we have defines an specific Interface.\n\n- **Single Instance**: Single Instance is based on singleton pattern and create an instance of class and share same instance between all dependencies. We use `ISingletonLifetime` to sign classes that are needed to be singleton.\n\n  \u003e This is also known as ‘singleton.’ Using single **instance** scope, **one instance is returned from all \\**request\\**s in the root and all nested scopes**.\n\n- **Instance Per Request**:  InstancePerRequest resolves dependencies per request. It means during processing a request if a service is injected and within inner dependencies, again the service is injected, both services refer to the same instance. We use `IScopedLifetime` to sign classes that are needed to be InstancePerRequest.\n\n  \u003e Some application types naturally lend themselves to “**request**” type semantics, for example ASP.NET [web forms](https://autofac.readthedocs.io/en/latest/integration/webforms.html) and [MVC](https://autofac.readthedocs.io/en/latest/integration/mvc.html) applications. In these application types, it’s helpful to have the ability to have a sort of “singleton **per** request.”\n\n- **Instance Per Dependency**: InstancePerDependency create a new instance per injection. We use `ITransientLifetime` to sign classes that are needed to be InstancePerRequest.\n\n  \u003e Also called ‘transient’ or ‘factory’ in other containers. Using **per**-dependency scope, **a unique \\**instance\\** will be returned from each \\**request\\** for a service.**\n\n\n\nThe following code indicates the `UserService` is implementation of `IUserService` and is signed with `ITransientLifetime` interface. When `IUserService` is injected to another class, Autofac due to `ITransientLifetime` creates a new instance of `UserService`. If instead of `ITransientLifetime`, `UserService` had been signed with `ISingletonLifetime`, the existing instance was injected (just once create a new instance).\n\n```c#\npublic class UserService : IUserService, ITransientLifetime\n{\n\t//Implementation.\n}\n```\n\n```C#\npublic class UserController : DavliControllerBase\n {\n\t\tprivate readonly IUserService _userService;\n    \n        public UserController(IUserService userService)\n        {\n            _userService = userService;\n        }\n\n}\n```\n\n\n\n`DavliDIModule` and `DIModule` are classes we have used to define `ITransientLifetime`, `IScopedLifetime`, and `ISingletonLifetime` behavior. Both of them are derived from `Autofac.Module` and override `Load` function. ThisAssembly says to Autofac to search current assembly and impose your role on classes that are derived from `ITransientLifetime`, `IScopedLifetime`, and `ISingletonLifetime`. DavliDIModule exists in the DavliFramework project and only registers roles for the DavliFramework project's classes. Also, DIModule exists in the current project (Sample.Api) and registers roles there.\n\n```c#\npublic class DavliDIModule : Module\n{\n    protected override void Load(ContainerBuilder builder)\n    {\n        builder.RegisterAssemblyTypes(ThisAssembly)\n            .Where(x =\u003e x.IsAssignableTo\u003cITransientLifetime\u003e()).AsSelf().AsImplementedInterfaces()\n            .InstancePerDependency();\n\n        builder.RegisterAssemblyTypes(ThisAssembly)\n            .Where(x =\u003e x.IsAssignableTo\u003cIScopedLifetime\u003e()).AsSelf().AsImplementedInterfaces()\n            .InstancePerRequest();\n\n        builder.RegisterAssemblyTypes(ThisAssembly)\n            .Where(x =\u003e x.IsAssignableTo\u003cISingletonLifetime\u003e()).AsSelf().AsImplementedInterfaces()\n            .SingleInstance();\n    }\n}\n```\n\n\n\nAlso, instead of registering both DavliDIModule and DIModule, you can ignore DavliDIModule and change DIModule as below. The following code says to Autofac search all *.dll in the build directory and imposes your role on classes that are derived from `ITransientLifetime`, `IScopedLifetime`, and `ISingletonLifetime` (not recommended).\n\n```c#\npublic class DIModule : Module\n{\n    protected override void Load(ContainerBuilder builder)\n    {\n\t\tvar assemblies = Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, \"*.dll\", SearchOption.TopDirectoryOnly)\n               .Select(Assembly.LoadFrom);\n\n\t\tbuilder.RegisterAssemblyTypes(assemblies.ToArray())\n\t\t\t.Where(x =\u003e x.IsAssignableTo\u003cITransientLifetime\u003e()).AsSelf().AsImplementedInterfaces().InstancePerDependency();\n\n\t\tbuilder.RegisterAssemblyTypes(assemblies.ToArray())\n\t\t\t.Where(x =\u003e x.IsAssignableTo\u003cIScopedLifetime\u003e()).AsSelf().AsImplementedInterfaces().InstancePerRequest();\n\n\t\tbuilder.RegisterAssemblyTypes(assemblies.ToArray())\n\t\t\t.Where(x =\u003e x.IsAssignableTo\u003cISingletonLifetime\u003e()).AsSelf().AsImplementedInterfaces().SingleInstance();\n    }\n\n}\n```\n\nYou can use `ContainerBuilder` in `Startup.ConfigureContainer` to register new roles and types. Also, you can use ASP.NET Core Ioc in `Startup.ConfigureServices` function.\n\n## Exceptions\n\nWhen an exception occurs in the system the action result will be such as the following object and response HttpStatusCode will be 4xx or 5xx. HttopStatusCode in the range of 4xx shows the exception is because of user behavior (client-side) and 5xx shows it has occurred because of system defects (server-side). In the SampleApi project, there is an `ExceptionController` that you can use to throw an exception and see the result.\n\n```json\n{\n  \"__unauthorizedRequest\": true,\n  \"__wrapped\": true,\n  \"__traceId\": \"\",\n  \"error\": {\n    \"errorCode\": \"USER_NOT_FOUND\",\n    \"message\": \"User not found.\",\n    \"details\": \"\",\n    \"source\": \"\"\n  }\n}\n```\n\n The above response had HttpStatusCode 404 that shows the not found exception has occured. Depend on the application is running on production or other environments, the `message`, `details`, and `source` can have more details about exceptions. \n\n- **__unauthorizedReques**t: shows the request is authorized or not. In the above example, the request is not authorized.\n- **__wrapped**: shows the result is wrapped or not. Now, by default, all exceptions are wrapped.\n- **__traceId**: TraceId will use to track a request over other systems and services. It is not implemented.\n- **error.errorCode**: ErrorCode shows the exception reason. When a developer throws a `DavliException`, he/she will fill this field.\n- **error.Message**: Message shows the exception reason.  \n- **error.Details**: Details shows details of exceptions such as stack trace and inner exception details. It is always empty in production environment.\n- **error.Source**: The source shows the service that has raised the exception. If you use microservice architecture, It would show the name of the service and its version. The following config is needed in `appsetting. json` (It is always empty in production).\n\n\n\n```json\n{\n  \"ServiceInfo\": {\n    \"Name\": \"Service Name\",\n    \"Description\": \"Service Description\",\n    \"Version\": \"1.0\"\n  }\n}\n```\n\n\n\nDavli has its Exception that is derived from Exception. Also, there are other exceptions that are derived from `DavliException`. We suggest to use `DavliException` and you can define new exceptions by driving `DavliException`. If you have defined a new exception that is derived from `DavliException`, check `GlobalExceptionFilter.cs` class for more details about exceptions.\n\n```c#\npublic class DavliException : Exception \n\n{\n    /// \u003csummary\u003e\n    /// Error code that indicates a summary of error by using some words or numbers.\n    /// \u003c/summary\u003e\n​\tpublic string ErrorCode { get; protected set; }\n    \n    /// \u003csummary\u003e\n    /// Technical-details are not allowed to be shown to the user.\n    /// Just log them or use them internally by software-technicians.\n    /// \u003c/summary\u003e\n    public string TechnicalMessage { get; protected set; }\n}\n```\n\n\n\n- **DavliException**: This exception use generally and its HttpStatusCode will be 500.\n\n- **DavliExceptionNotFound**: This exception use to show NotFoundException and HttpStatusCode will be 404.\n\n- **DavliExceptionInvalidParameter**: This exception use to show InvalidParameter and HttpStatusCode will be 422.\n\n- **DavliBusinessException**: This exception use to show BusinessException and HttpStatusCode will be 400 (recommended for exceptions that should be thrown because of a business defect).\n\n- **DavliExceptionBadRequest**: This exception use to show BadRequestand HttpStatusCode will be 400.\n\n- **DavliExceptionExternalService**: This exception shows during calling other API an exception has occurred and its HttpStatusCode can be set manually.\n\n- **Exception**:  This exception use generally and its HttpStatusCode will be 500.\n\n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnigje%2Fdavli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnigje%2Fdavli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnigje%2Fdavli/lists"}