preface

Not afraid of clouds, only in the mountains. — Wang Anshi, “Climbing The Mountain”

My previous article, “why do I recommend you build large backend applications in C#? – Part 1,” demonstrated the popularity of C# and introduced some of its unique syntactic features as a starting point for analyzing the advantages of C# for building back-end applications. In this article, we’ll continue to explore some of the other features of C# to further demonstrate the benefits and scenarios of using C# for back-end development. In this article, the second in a series on C#, we will use.net Core, the C# cross-platform framework, as an example of how to write large back-end application projects in C#.

The.net Core description

As mentioned in the previous article, C# is the main support language of.net..net is a platform development framework developed by Microsoft and open source. Similar to Java Spring, it is a very comprehensive software development framework, which can develop Web applications, apis, cloud functions, mobile terminals, etc. Integrates various suites that developers need. One of the reasons.net has been criticized in the past is that it can only be deployed on Windows operating systems, which makes it difficult to popularize C# and.net. Fortunately, Microsoft released.net Core in 2016, which enables C# applications to run across platforms, not only on Windows, but also on MacOS and Linux. The release of.net Core makes C# independent of Windows and an enterprise-level programming language independent of operating systems, putting it on a par with Java, which runs across JVM platforms. Indeed, there are many areas where C# has an advantage over Java, such as syntax features.

Nowadays, many enterprises have adopted.NET Core as the back-end development framework, because it is simple and comprehensive enough that many functional modules can be deployed out of the box, and can be deployed on CentOS, Ubuntu and other operating systems, or deployed in distributed clusters as containers. With the development of container choreography, microservices and other technologies,.NET Core, as a modern backend development framework, can be used to develop scalable, easy to maintain large backend systems, and the corresponding ecological technology can make it suitable for more business scenarios.

An overview of the backend framework

Front end separation is the mainstream architecture design of modern Web applications. The front end is usually a one-page application (SPA) developed by front-end frameworks such as React and Vue, and the back end is usually a RESTful API based on HTTP. Data interaction between the front end and back end is completed through AJAX requests. Back-end API development is where.NET Core excels.

The following are common modules or functions in Web API development, and only the common module functions in back-end applications are listed here.

  • routing
  • The middleware
  • Authentication/authorization
  • Database operations
  • configuration
  • Dependency injection
  • The log
  • Error handling
  • Unit testing
  • RPC

As you can see, a mature back-end Web framework still needs to cover a lot of ground. .net Core, as a modern back-end framework, contains all of these generic modules and functions. Therefore, using.NET Core directly to develop back-end Web apis simplifies a lot of setup work because these features are easy to implement out of the box. In addition, Microsoft has written a very detailed documentation for.NET Core. For developers who are new to or unfamiliar with.NET Core, they can read the documentation to help them quickly grasp the basics and apis. To speed up the beginning of developing back-end API applications using.NET Core.

Web frameworks in other programming languages (such as Spring Boot, Gin) contain similar functional modules, and some of the base modules are very similar. However, I think.net Core has some advantages for improving the development experience, such as database operations, authentication/authorization, dependency injection, etc. This article will introduce these modules to the main features of.NET Core.

Below, I’ll focus on these key features of.NET Core for developing back-end apis.

Key features of.NET Core

Here we highlight some of.net Core’s developer-friendly features that are key to improving the development experience and efficiency. We’ll skip over the general features of routing, middleware, and unit testing, all of which are pretty much the same, and you can refer to the official documentation for details.

Database operations

Entity Framework (EF for short) is the main database operation Framework used by.NET Core. EF is C# exclusive modern ORM framework, mainly used to operate relational database data, tables, columns, fields and other database objects. Entity Framework works with LINQ, an sql-like query language detailed in the previous article, why are you building large backend applications in C#? – Part 1, to easily perform ORM queries and operations in your code.

The query

Here is a simple EF query language example.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Where(b => b.Url.Contains("dotnet"))
        .ToList();
}
Copy the code

BloggingContext is a database context class in EF, which contains relevant database tables, columns, fields, indexes, foreign keys, etc., and can be directly manipulated in C# code. Contains(“dotnet”) is an anonymous function that defines the filter conditions. The parameter b is each row in the table. It contains the Url field.

Of course, Entity Framework’s query capabilities go far beyond that, and it can do almost anything SQL can do.

Here is a relatively complex LINQ query statement with a JOIN.

var query = from photo in context.Set<PersonPhoto>()
            join person in context.Set<Person>()
                on new { Id = (int?). photo.PersonPhotoId, photo.Caption }equals new { Id = person.PhotoId, Caption = "SN" }
            select new { person, photo };
Copy the code

In this query, the PersonPhoto and Person tables JOIN the PersonPhotoId and PhotoId fields and filter out the entries with the Caption equal to SN. Finally, the person and photo models are output. The end result is a list of items containing the Person and photo models.

As you can see, using LINQ to query a relational database in EF is as simple as writing SQL. Furthermore, the main reason we use ORM to manipulate the database in C# code is to constrain variable types and keep the code statically typed.

operation

The add, Delete, modify, and Query (CURD) module is almost indispensable to a general Web API. We introduced EF’s ease of query, and now we introduce EF’s other data manipulation methods, namely add, delete, and modify.

The following is a simple example of adding, deleting, and changing an EF.

/ / add
using (var context = new BloggingContext())
{
    var blog = new Blog { Url = "http://example.com" };
    context.Blogs.Add(blog);
    context.SaveChanges();
}

/ / delete
using (var context = new BloggingContext())
{
    var blog = context.Blogs.First();
    context.Blogs.Remove(blog);
    context.SaveChanges();
}

/ / update
using (var context = new BloggingContext())
{
    var blog = context.Blogs.First();
    blog.Url = "http://example.com/blog";
    context.SaveChanges();
}
Copy the code

Blogs Add, Remove, and attribute assignment (blog.url =…). It’s also relatively simple.

Syntactic consistency

Please note that the above is the basic syntax for the ICollection interface and type instances in C#. There is nothing additional, which means that the Entity Framework is fully compatible with C# base types with strong syntactic consistency.

Why is syntactic type consistency an important feature to improve the development experience? First, from a working brain perspective, it reduces unnecessary working memory overhead, because you don’t need more working memory areas (such as new grammar) to help you with your work, thus making your development more efficient and avoiding the productivity issues associated with working memory switching. Second, syntactic consistency allows developers to standardize code more properly, using programming patterns in the underlying syntax to standardize code in ORM. Third, learning costs are reduced because developers don’t need to learn new things.

On the contrary, if you go to learn Java MyBatis, JPA ORM framework, you need to master a lot of extra knowledge, in order to effectively complete the database add, delete, change and search operations.

One of the main reasons I recommend writing backend applications in C# is the Entity Framework. Using EF to operate a database in.NET Core is a great way to achieve syntactic consistency, improve development experience and productivity.

Dependency injection

.NET Core, like other large backend frameworks, has Dependency Injection (DI) capabilities. What is dependency injection? In fact, dependency injection is not a new concept, but a design pattern in software engineering, which is mainly used to reduce the complexity of dependencies between modules and achieve the purpose of decoupling. In simple terms, dependency injection allows developers to “inject” (or register) all dependencies into containers. If a dependency is needed, it can be directly referenced by a type or interface, without the developer having to worry about dependencies between modules. This is very useful in object-oriented programming (OOP) languages.

Dependency injection is not limited to OOP. Angular, for example, has dependency injection as its modular core, and there is a dependency injection framework in the Go language. You can refer to Microsoft’s official documentation on dependency injection for an in-depth understanding of the concept.

.net Core advocates a dependency injection approach to project structure. Modularity and layering are important for large projects, and this can be achieved through dependency injection.

Here is an example of using dependency injection to layer the controller layer responsible for handling HTTP request responses from the service layer responsible for implementing the core business logic.

We first define the model, service interface, and service class.

// ./Interfaces/IUserService.cs.namespace DotNetExamples.Interfaces
{
    public interface IUserService
    {
        IEnumerable<User> GetUserList(); . }}// ./Services/UserService.cs.namespace DotNetExamples.Services
{
    public class UserService : IUserService
    {
        public IEnumerable<User> GetUserList()
        {
            // Get the core code of the data. }... }}Copy the code

We then register the service in the Startup code startup. cs.

// ./Startup.cs.public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
  
            // Register serviceservices.AddScoped<IUserService, UserService>(); }...Copy the code

Services.addscoped

(); This is the code to register the user service. AddScoped means that the dependency has a scoped lifetime, that is, in a context that exists only once. One benefit of.NET Core is that you can tune performance by configuring the dependent lifecycle. The dependency injection lifecycle is not covered here for space reasons, but you can check it out on the Microsoft.net Core website.
,>

We can then refer to the service through the interface in the controller code. Here is the code for the controller UserController.

// ./Controllers/UserController.cs.namespace DotNetExamples.Controllers{[ApiController]
    [Route("[controller]")]
    public class UserController : ControllerBase
    {
        // Declare dependencies
        private readonly IUserService _userService;
        
        public UserController(IUserService userService)
        {
            // Inject dependencies
            _userService = userService;
        }

        [HttpGet]
        public IEnumerable<User> GetList()
        {
            // Invoke dependencies
            return_userService.GetUserList(); }}}Copy the code

As you can see, the related dependency IUserService is injected in the form of a constructor. Just declare the private variables and inject the dependencies into the constructor, ignoring the details of dependencies and simply referring to them. It’s pretty straightforward.

If you look closely at the example above, you can see that the controller, UserController, simply declares the route, and its core code for getting data is in the GetUserList method of the injected UserService type dependent _userService. In this way, it is easy to separate the Controller layer, which is responsible for HTTP data interaction, from the Service layer, which is responsible for the actual business logic, so as to realize the design concept of low coupling in software engineering.

conclusion

This article introduces two of the key features of.net Core, the C# cross-platform framework, to help readers understand the advantages of developing backend projects in C#. Entity Framework makes it very easy and flexible to write CURD applications with.NET Core because of its syntactical consistency and syntax simplicity with LINQ support. In addition, we introduced dependency injection for.NET Core, which makes it easier to layer, modularize, and implement low-coupling designs for project code. The Controller layer and Service layer can be separated from each other without being affected, which increases maintainability and extensibility.

This article is the second in a series of articles, c # behind the author will introduce more c # to build large-scale backend application practice content, in order to help interested readers to better understand and familiar with c #, help you broaden the knowledge and increase especially backend software engineering development in the breadth of knowledge, let developers in the back-end programming languages can have more choice, Such as c #.