sulmar / altkom-dotnet-core-201910

Przykłady ze szkolenia .NET Core
http://www.altkom.pl
0 stars 0 forks source link
net-core-2-2 netcore2-webapi szkolenie

.NET Core

Przydatne komendy CLI

Struktura projektu

+ Solution
   |
   + - Console

   |
   + - Models
   |
   + - Infrastructure
   |
   + - Api

HTTP Client

public async Task<IEnumerable> Get(CustomerSearchCriteria customerSearchCriteria) { var url = $"{baseUri}/api/customers";

url = AddQueryCustomerParams(customerSearchCriteria, url);

var json = await url.GetJsonFromUrlAsync();

var customers = json.FromJson<ICollection>();

return customers; }

private static string AddQueryCustomerParams(CustomerSearchCriteria searchCriteria, string url) { if (!string.IsNullOrEmpty(searchCriteria.CustomerNumber)) url = url.AddQueryParam(nameof(CustomerSearchCriteria.CustomerNumber), searchCriteria.CustomerNumber);

  if (!string.IsNullOrEmpty(searchCriteria.City))
      url = url.AddQueryParam(nameof(CustomerSearchCriteria.City), searchCriteria.City);

  if (!string.IsNullOrEmpty(searchCriteria.Street))
      url = url.AddQueryParam(nameof(CustomerSearchCriteria.Street), searchCriteria.Street);

  if (!string.IsNullOrEmpty(searchCriteria.Country))
      url = url.AddQueryParam(nameof(CustomerSearchCriteria.Country), searchCriteria.Country);

  return url;

}


## .NET Standard

.NET Framework | .NET Core |

.NET Standard


## Protokół HTTP

żądanie (request)

GET /docs/index.html HTTP/1.1 host: www.altkom.pl {blank line}


odpowiedź (response)

HTTP/1.1 200 OK Content-Length: 308 Content-Type: text/html

Hello World!


----

żądanie (request)

GET /api/customers HTTP/1.1 host: www.altkom.pl Accept: application/json {blank line}


odpowiedź (response)

HTTP/1.1 200 OK Content-Length: 308 Content-Type: application/xml

John

## SOAP 
żądanie (request)

POST /myservice.asmx HTTP/1.1 host: www.altkom.pl Content-Type: application/xml

John

## REST API

| Akcja  | Opis                  |
|--------|-----------------------|
| GET    | Pobierz               |
| POST   | Utwórz                |
| PUT    | Podmień               |
| DELETE | Usuń                  |
| PATCH  | Zmień częściowo       |
| HEAD   | Czy zasób istnieje    |

prawidłowe

GET api/customers GET api/customers/10 GET api/customers/altkom GET api/customers?city=Katowice&Street=Opolska DELETE api/customers/10


nieprawidłowe

GET api/customers?Id=10 GET api/customers/delete?Id=10 GET api/customers/GetCustomerByCity?city=Poznan


## Porównanie ASP.NET MVC i .NET Core

ASP.NET MVC 

Controller ApiController View(model) Ok(model)


.NET Core

Controller -> BaseController View(model) Ok(model)


## Wstrzykiwanie zależności

DI/IoC 

~~~ csharp
interface Factory
{
   T Create<T>();
}
| Key                    | Value                  | Cykl zycia
| ICustomerRepository   | FakeCustomerRepository | Singleton
| CustomerFaker        | CustomerFaker          |
| AddressFaker         | AddressFaker           |

Baza danych

Konfiguracja

{
  "CustomersModule": {
    "Quantity": 40
  },
 dotnet add package Microsoft.Extensions.Options

public class FakeCustomersService
{
   private readonly CustomerOptions options;

    public FakeCustomersService(IOptions<CustomerOptions> options)
    {
        this.options = options.Value;
    }
}
public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false)
                .AddXmlFile("appsettings.xml", optional: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

            Configuration = builder.Build();

        }

      public void ConfigureServices(IServiceCollection services)
      {
          services.Configure<CustomerOptions>(Configuration.GetSection("CustomersModule"));
      }
    }
  public void ConfigureServices(IServiceCollection services)
        {
            var customerOptions = new CustomerOptions();
            Configuration.GetSection("CustomersModule").Bind(customerOptions);
            services.AddSingleton(customerOptions);

            services.Configure<CustomerOptions>(Configuration.GetSection("CustomersModule"));
        }

Opcje serializacji json

Plik Startup.cs


public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc()
    .AddJsonOptions(options =>
    {
        options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; // Wyłączenie generowania wartości null w jsonie
        options.SerializerSettings.Converters.Add(new StringEnumConverter(camelCaseText: true));  // Serializacja enum jako tekst
        options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; // Zapobieganie cyklicznej serializacji

    })
}

Włączenie obsługi XML

Plik Startup.cs

 public void ConfigureServices(IServiceCollection services)
 {
     services
         .AddMvc(options => options.RespectBrowserAcceptHeader = true)
         .AddXmlSerializerFormatters();
 }

Task


  t1    -----+=============+------------------->

  t1    -----+-------+------------------------>
         |       |        |
  t2    -----+=============|------------------>
                 |        |
  t3    -------------+=============|---------->
                              |
  t4    ----------------------+=======|------->

Middleware

       middleware (filter)
   request -> ----|---|-----|-----|-----|===Get(100)====|---response--------> 

Autoryzacja

Basic

Headers Key Value
Authorization Basic {Base64(login:password)}

Implementacja

public class DbCustomerRepository : ICustomerRepository
{
     private readonly MyContext context;

     public DbCustomerRepository(MyContext context)
     {
         this.context = context;
     }

     public bool TryAuthorize(string username, string hashPasword, out Customer customer)
     {
         customer = context.Customers.SingleOrDefault(e => e.UserName == username && e.HashPassword == hashPasword);

         return customer != null;
     }
 }
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        private readonly ICustomerRepository customerRepository;

        public BasicAuthenticationHandler(
            ICustomerRepository customerRepository,
            IOptionsMonitor<AuthenticationSchemeOptions> options, 
            ILoggerFactory logger, 
            UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
        {
            this.customerRepository = customerRepository;
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!Request.Headers.ContainsKey("Authorization"))
                return AuthenticateResult.Fail(string.Empty);

            var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);

            if (authHeader.Scheme != "Basic")
                return AuthenticateResult.Fail(string.Empty);

            var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
            string[] credentials = Encoding.UTF8.GetString(credentialBytes).Split(':');

            if (!customerRepository.TryAuthorize(credentials[0], credentials[1], out Customer customer))
            {
                return AuthenticateResult.Fail("Invalid username or password");
            }

            ClaimsIdentity identity = new ClaimsIdentity("Basic");

            identity.AddClaim(new Claim(ClaimTypes.HomePhone, "555-444-333"));
            identity.AddClaim(new Claim(ClaimTypes.Role, "Developer")); 

            ClaimsPrincipal principal = new ClaimsPrincipal(identity);

            var ticket = new AuthenticationTicket(principal, "Basic");

            return AuthenticateResult.Success(ticket);

        }
    }
 public void ConfigureServices(IServiceCollection services)
{

    services.AddAuthentication("BasicAuthorization")
        .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthorization", null);
  }

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  {

      app.UseAuthentication();
      app.UseMvc();
    }

Token

Headers Key Value
Authorization Bearer {token}

Generowanie dokumentacji

W formacie Swagger/OpenApi

Instalacja

dotnet add package Swashbuckle.AspNetCore

Konfiguracja

Plik Startup.cs

public void ConfigureServices(IServiceCollection services)
{
 services
      .AddSwaggerGen(c => c.SwaggerDoc("v1", new Info { Title = "My Api", Version = "1.0" }));         
} 
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   app.UseSwagger();

   app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"));
 }