ASP.NET Core

1] How to publish an ASP.NET Core project?

$ dotnet publish -c Release -o /var/www/html

$ sudo systemctl restart htmlaspnet.service

 

2] MVC is a wide-used architectural pattern that separates an application into three district components to manage complexity and promote code reuse.

Model presents your data and business logic. It is consisted of classes with properties.

View is the user interface which is responsible for displaying the data from the model.

Controller acts as the intermediary between the mode and the view.

 

3] Razor Pages is a simpler, page-focused framework that was introduced to make building web application easier.

A .cshtml page is the view, containing the HTML and Razor markup for the page.

A .cshtml.cs file is the page model or code-behind file to handle requests for the page.

 

 

+ Properties \
+ wwwroot \
    + css\
    + js\
    + lib\
    – favicon.ico
+ Controllers \
+ Models \
+ Views \
    + Home \
        – Index.cshtml
        – Privacy.cshtml
    + Share \
        – _Layout.cshtml
        – _ValidationScriptsPartial.cshtml
        – Error.cshtml
    – _viewImports.cshtml
    – _viewStart.cshtml
– appsettings.json
– program.cs

 

// Returns an instance of WebApplicationBuilder class
var builder = WebApplication.CreateBuilder(args);
// Returns an instance of WebApplication
var app = builder.Build();
// Creating a route – HTTP metho + URL
app.MapGet(“/”, () => “Hello World”);
// Starging the server
app.Run();
Packages
Microsoft.AspNetCore.Identity.EntityFrameworkCore     8.0.11
Microsoft.AspNetCore.Identity.UI                                    8.0.11
Microsoft.EntityFrameworkCore.Design                         8.0.11
Microsoft.EntityFrameworkCore.SqlServer                     8.0.11
Microsoft.EntityFrameworkCore.Tools                            8.0.11
Microsoft.VisualStudio.Web.CodeGeneration.Design     8.0.7
Npgsql.EntityFrameworkCore.PostgreSQL                     8.0.11
Project > Add > New Scaffolded Item > Identity > Add > Add Identity
1. Choose files to override
    Account\Login
    Account\Register
2. DbContext class
    AuthSystem.Data.AuthDbContext
3. User class
    ApplicationUser
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(20);
    options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
app.UseSession();
using Microsoft.AspNetCore.Mvc;
public class AccountController : Controller
{public IActionResult Login()
{
return View();
}
    [HttpPost]
public IActionResult Login(string username, string password)
{if (username == “test” && password == “1234”)
{ HttpContext.Session.SetString(“Username”, username);
HttpContext.Session.SetInt32(“UserId”, 1001);
             return RedirectToAction(“Profile”);
}
        ViewBag.ErrorMessage = “아이디 또는 비밀번호가 일치하지 않습니다.”;
return View();
}
    public IActionResult Profile()
{
var username = HttpContext.Session.GetString(“Username”);
var userId = HttpContext.Session.GetInt32(“UserId”);
if (string.IsNullOrEmpty(username) || userId == null)
{
return RedirectToAction(“Login”);
}
        ViewBag.Username = username;
ViewBag.UserId = userId;return View();
}
    public IActionResult Logout()
{HttpContext.Session.Clear();
return RedirectToAction(“Login”);
}
}
using System.Text.Json;
namespace html_csneutrons.Extensions
{
public static class SessionExtensions
{
public static void Set<T>(this ISession session, string key, T value)
{
            string jsonString = JsonSerializer.Serialize(value);
            session.SetString(key, jsonString);
}
        public static T Get<T>(this ISession session, string key)
{
            var jsonString = session.GetString(key);
            if (string.IsNullOrEmpty(jsonString))
{
return default(T);
}
            return JsonSerializer.Deserialize<T>(jsonString);
}
}
}
HttpContext.Session.Set<UserViewModel>(“LoggedInUser”, user);
var user = HttpContext.Session.Get<UserViewModel>(“LoggedInUser”);
public class UserViewModel
{
public int Id { get; set; }
public string Username { get; set; }
public string[] Roles { get; set; }
}
public class AccountController : Controller
{
[HttpPost]
public IActionResult Login(string username, string password)
{
if (username == “test” && password == “1234”)
{
var user = new UserViewModel
{
Id = 1001,
Username = “test”,
Roles = new string[] { “Admin”, “User” }
};
HttpContext.Session.SetObjectAsJson(“CurrentUser”, user);
            return RedirectToAction(“Profile”);
}
return View();
}
    public IActionResult Profile()
{var user = HttpContext.Session.GetObjectFromJson<UserViewModel>(“CurrentUser”);
        if (user == null)
{
return RedirectToAction(“Login”);
}
        // 뷰로 모델 전달
return View(user);
}}
Microsoft.Extensions.Caching.StackExchangeRedis
var builder = WebApplication.CreateBuilder(args);
// …
// Redis를 분산 캐시로 등록
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString(“Redis”);
options.InstanceName = “SampleInstance_”; // 키 충돌 방지를 위한 접두사
});
// 세션 서비스 등록 (이제 세션은 Redis에 저장됩니다)
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(20);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
// …
Models / LoginModel.cs
using Dapper;
using html_csneutrons.Interfaces;
namespace html_csneutrons.Models
{
}
    public class Login
{
public int login_id { get; set; }
public string username { get; set; }
public int membership_id { get; set; }
public string password { get; set; }
public string info_json { get; set; }
public DateTime mod_date { get; set; }
}
   public interface ILoginModel
{
Task<Login?> GetByIdAsync(int login_id);
Task<IEnumerable<Login>> GetAllAsync();
   }
    public class LoginModel: ILoginModel
    {
private readonly INpgDbConnectionFactory _dbConnectionFactory;
        public LoginModel(INpgDbConnectionFactory dbConnectionFactory)
        {
_dbConnectionFactory = dbConnectionFactory;
}
        public async Task<Login?> GetByIdAsync(int login_id)
{
using var connection = await _dbConnectionFactory.CreateConnectionAsync();
            const string sql = “SELECT * FROM public.\”AMMS_Login\” WHERE login_id = @login_id”;
            return await connection.QuerySingleOrDefaultAsync<Login>(sql, new { login_id = login_id });
}
        public async Task<IEnumerable<Login>> GetAllAsync()
{
using var connection = await _dbConnectionFactory.CreateConnectionAsync();
const string sql = “SELECT * FROM public.\”AMMS_Login\””;
return await connection.QueryAsync<Login>(sql);
}
    }
Program.cs
using html_csneutrons.Models;
builder.Services.AddScoped<ILoginModel, LoginModel>();
Controllers / LoginController.cs
using Microsoft.AspNetCore.Mvc;
using html_csneutrons.Models;
namespace html_csneutrons.Controllers
{
// https://localhost:7137/api/login/13681
[ApiController]
[Route(“api/[controller]”)]
public class LoginController : Controller
    {
private readonly ILoginModel _loginModel;
        public LoginController(ILoginModel loginModel)
        {
_loginModel = loginModel;
      }
 
        [HttpGet(“{login_id}”)]
public async Task<IActionResult> GetLoginById(int login_id)
{
            var login = await _loginModel.GetByIdAsync(login_id);
if (login == null)
{
                return NotFound();
}
return Ok(login);
}
  }
}
@
{
Layout = “/Views/Shared/_Layout.cshtml”;
}
HTML
<div class=”row justify-content-center”>
    <div class=”col-5 mt-5″>
<div class=”card login-logout-card”>
<div class=”card-header”>
<ul class=”nav nav-tabs card-header-tabs”>
<li class=”nav-item”>
<a class=”nav-link” href=”/Identity/Account/Login”>
Log In
</a>
</li>
<li class=”nav-item”>
<a class=”nav-link” href=”/Identity/Account/Register”>
Register
</a>
</li>
                </ul>
</div>
<div class=”card-body”>
<div class=”row justify-content-center”>
<div class=”col-10 my-4″>
@RenderBody()
</div>
</div>
</div>
</div>
</div>
</div>
Script
@section Scripts {
@await RenderSectionAsync(“Scripts”, required: false)
<script>
$(function (){
            const currentPage = location.pathname;
console.log(currentPage); // /Identity/Account/Login
$(‘.nav-tabs li a’).each(function (){
const $this = $(this);
if(currentPage.toLocaleLowerCase().indexOf($this.attr(‘href’).toLocaleLowerCase()) !== -1){
$this.addClass(‘active’);
}
});
});
</script>
}

 

 

 

@page
@model RegisterModel
@{
ViewData[“Title”] = “Register”;
Layout = “~/Areas/Identity/Pages/_AuthLayout.cshtml”;
}
<form id=”registerForm” asp-route-returnUrl=”@Model.ReturnUrl” method=”post”>
    ….
</form>
@section Scripts {
<partial name=”_ValidationScriptsPartial” />
}
<form id=”registerForm” asp-route-returnUrl=”@Model.ReturnUrl” method=”post”>
<h2>Create a new account.</h2>
<hr />
<div asp-validation-summary=”ModelOnly” class=”text-danger” role=”alert”></div>
<div class=”row”>
<div class=”col-6″>
<div class=”form-floating mb-3″>
<input asp-for=”Input.FirstName” class=”form-control” autocomplete=”firstname” aria-required=”true” placeholder=”first name” />
<label asp-for=”Input.FirstName”>First Name</label></div>
</div>
<div class=”col-6″>
<div class=”form-floating mb-3″>
<input asp-for=”Input.LastName” class=”form-control” autocomplete=”lastname” aria-required=”true” placeholder=”last name” />
<label asp-for=”Input.LastName”>Last Name</label></div>
</div>
    </div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.Email” class=”form-control” autocomplete=”username” aria-required=”true” placeholder=”name@example.com” />
<label asp-for=”Input.Email”>Email</label>
<span asp-validation-for=”Input.Email” class=”text-danger”></span>
</div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.Password” class=”form-control” autocomplete=”new-password” aria-required=”true” placeholder=”password” />
<label asp-for=”Input.Password”>Password</label>
<span asp-validation-for=”Input.Password” class=”text-danger”></span>
</div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.ConfirmPassword” class=”form-control” autocomplete=”new-password” aria-required=”true” placeholder=”password” />
<label asp-for=”Input.ConfirmPassword”>Confirm Password</label>
<span asp-validation-for=”Input.ConfirmPassword” class=”text-danger”></span>
</div>
<button id=”registerSubmit” type=”submit” class=”w-100 btn btn-lg btn-primary”>Register</button>
</form>
@page
@model RegisterModel
@{
ViewData[“Title”] = “Register”;
Layout = “~/Areas/Identity/Pages/_AuthLayout.cshtml”;
}
<form id=”registerForm” asp-route-returnUrl=”@Model.ReturnUrl” method=”post”>
    ….
</form>
@section Scripts {
<partial name=”_ValidationScriptsPartial” />
}
<form id=”registerForm” asp-route-returnUrl=”@Model.ReturnUrl” method=”post”>
<h2>Create a new account.</h2>
<hr />
<div asp-validation-summary=”ModelOnly” class=”text-danger” role=”alert”></div>
<div class=”row”>
<div class=”col-6″>
<div class=”form-floating mb-3″>
<input asp-for=”Input.FirstName” class=”form-control” autocomplete=”firstname” aria-required=”true” placeholder=”first name” />
<label asp-for=”Input.FirstName”>First Name</label></div>
</div>
<div class=”col-6″>
<div class=”form-floating mb-3″>
<input asp-for=”Input.LastName” class=”form-control” autocomplete=”lastname” aria-required=”true” placeholder=”last name” />
<label asp-for=”Input.LastName”>Last Name</label></div>
</div>
    </div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.Email” class=”form-control” autocomplete=”username” aria-required=”true” placeholder=”name@example.com” />
<label asp-for=”Input.Email”>Email</label>
<span asp-validation-for=”Input.Email” class=”text-danger”></span>
</div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.Password” class=”form-control” autocomplete=”new-password” aria-required=”true” placeholder=”password” />
<label asp-for=”Input.Password”>Password</label>
<span asp-validation-for=”Input.Password” class=”text-danger”></span>
</div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.ConfirmPassword” class=”form-control” autocomplete=”new-password” aria-required=”true” placeholder=”password” />
<label asp-for=”Input.ConfirmPassword”>Confirm Password</label>
<span asp-validation-for=”Input.ConfirmPassword” class=”text-danger”></span>
</div>
<button id=”registerSubmit” type=”submit” class=”w-100 btn btn-lg btn-primary”>Register</button>
</form>

 

Namespace
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using html_csneutrons.Areas.Identity.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
namespace html_csneutrons.Areas.Identity.Pages.Account
{
    public class RegisterModel : PageModel
    ….
}
Class ReisterModel
public class RegisterModel : PageModel
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IUserStore<ApplicationUser> _userStore;
private readonly IUserEmailStore<ApplicationUser> _emailStore;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
    public RegisterModel(
UserManager<ApplicationUser> userManager,
IUserStore<ApplicationUser> userStore,
SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_userStore = userStore;
_emailStore = GetEmailStore();
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
    [BindProperty]
public InputModel Input { get; set; }
    public string ReturnUrl { get; set; }
    public IList<AuthenticationScheme> ExternalLogins { get; set; }
    public class InputModel ….
    public async Task OnGetAsync(string returnUrl = null) ….
    public async Task<IActionResult> OnPostAsync(string returnUrl = null) ….
    public async Task<IActionResult> OnPostAsync(string returnUrl = null) ….
    private ApplicationUser CreateUser() ….
    private IUserEmailStore<ApplicationUser> GetEmailStore() ….
}
InputModel
        public class InputModel
{
[DataType(DataType.Text)]
[Display(Name = “First Name”)]
public string FirstName { get; set; }
[DataType(DataType.Text)]
[Display(Name = “Last Name”)]
public string LastName { get; set; }
[Required]
[EmailAddress]
[Display(Name = “Email”)]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = “The {0} must be at least {2} and at max {1} characters long.”, MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = “Password”)]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = “Confirm password”)]
[Compare(“Password”, ErrorMessage = “The password and confirmation password do not match.”)]
public string ConfirmPassword { get; set; }
}
OnGetAsync
        public async Task OnGetAsync(string returnUrl = null)
{
            if (User.Identity.IsAuthenticated)
{
Response.Redirect(“/”);
}
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}
OnPostAsync
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content(“~/”);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = CreateUser();
                user.FirstName = Input.FirstName;
                user.LastName = Input.LastName;
                await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
var result = await _userManager.CreateAsync(user, Input.Password);
                if (result.Succeeded)
{
_logger.LogInformation(“User created a new account with password.”);
                    var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
“/Account/ConfirmEmail”,
pageHandler: null,
values: new { area = “Identity”, userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
                    await _emailSender.SendEmailAsync(Input.Email, “Confirm your email”,
$”Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}’>clicking here</a>.”);
                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage(“RegisterConfirmation”, new { email = Input.Email, returnUrl = returnUrl });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
            // If we got this far, something failed, redisplay form
return Page();
}
CreateUser()
        private ApplicationUser CreateUser()
{
try
{
return Activator.CreateInstance<ApplicationUser>();
}
catch
{
throw new InvalidOperationException($”Can’t create an instance of ‘{nameof(ApplicationUser)}’. ” +
$”Ensure that ‘{nameof(ApplicationUser)}’ is not an abstract class and has a parameterless constructor, or alternatively ” +
$”override the register page in /Areas/Identity/Pages/Account/Register.cshtml”);
}
}
GetEmailStore()
private IUserEmailStore<ApplicationUser> GetEmailStore()
{
if (!_userManager.SupportsUserEmail)
{
throw new NotSupportedException(“The default UI requires a user store with email support.”);
}
return (IUserEmailStore<ApplicationUser>)_userStore;
}
@page
@model LoginModel
@{
ViewData[“Title”] = “Log in”;
Layout = “~/Areas/Identity/Pages/_AuthLayout.cshtml”;
}
<div class=”row justify-content-center”>
    ….
</div>
@section Scripts {
<partial name=”_ValidationScriptsPartial” />
}
Form
<div class=”row justify-content-center”>
<div class=”col-10″>
<section>
<form id=”account” method=”post”>
<h2>Welcome back!</h2>
<hr />
<div asp-validation-summary=”ModelOnly” class=”text-danger” role=”alert”></div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.Email” class=”form-control” autocomplete=”username” aria-required=”true” placeholder=”name@example.com” />
<label asp-for=”Input.Email” class=”form-label”>Email</label>
<span asp-validation-for=”Input.Email” class=”text-danger”></span>
</div>
<div class=”form-floating mb-3″>
<input asp-for=”Input.Password” class=”form-control” autocomplete=”current-password” aria-required=”true” placeholder=”password” />
<label asp-for=”Input.Password” class=”form-label”>Password</label>
<span asp-validation-for=”Input.Password” class=”text-danger”></span>
</div>
<div class=”checkbox mb-3″>
<label asp-for=”Input.RememberMe” class=”form-label”>
<input class=”form-check-input” asp-for=”Input.RememberMe” />
@Html.DisplayNameFor(m => m.Input.RememberMe)
</label>
</div>
<div>
<button id=”login-submit” type=”submit” class=”w-100 btn btn-lg btn-primary”>Log in</button>
</div>
</form>
</section>
</div>
</div>
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using html_csneutrons.Areas.Identity.Data;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace html_csneutrons.Areas.Identity.Pages.Account
{
public class LoginModel : PageModel
}
    public class LoginModel : PageModel
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
        public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
        [BindProperty]
public InputModel Input { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
public string ReturnUrl { get; set; }
[TempData]
public string ErrorMessage { get; set; }
        public class InputModel
{[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = “Remember me?”)]
public bool RememberMe { get; set; }
}
        public async Task OnGetAsync(string returnUrl = null)
{
          if (User.Identity.IsAuthenticated)
            {
                Response.Redirect(“/”);
            }
            if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
            returnUrl ??= Url.Content(“~/”);
            // Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            ReturnUrl = returnUrl;
}
        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content(“~/”);
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
{
// This doesn’t count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation(“User logged in.”);
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage(“./LoginWith2fa”, new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning(“User account locked out.”);
return RedirectToPage(“./Lockout”);
}
else
{
ModelState.AddModelError(string.Empty, “Invalid login attempt.”);
return Page();
}
}
            // If we got this far, something failed, redisplay form
return Page();
}

“ConnectionStrings”: {
“AUTHDBCONTEXTCONNECTION”: “Server=localhost;Port=5432;Database=;User Id=postgres;Password=;”
},

var connectionString = Environment.GetEnvironmentVariable(“AUTHDBCONTEXTCONNECTION”);
builder.Services.AddSingleton<INpgDbConnectionFactory, NpgSqlConnectionFactory>();
builder.Services.AddDbContext<AuthDbContext>(options => options.UseNpgsql(connectionString));
builder.Services.AddDbContext<AppDbContext>(options => options.UseNpgsql(connectionString));

 

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<AuthDbContext>();

 

builder.Services.AddScoped<ILoginModel, LoginModel>();
builder.Services.AddScoped<IUserModel, UserModel>();

 

builder.Services.AddControllersWithViews();

 

builder.Services.AddRazorPages();

builder.Services.Configure<IdentityOptions>(options =>
{
options.Password.RequireUppercase = false;
});

builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File(
“logs/myapp-.txt”, // 로그 파일 경로. “logs/myapp-20231027.txt” 형식으로 생성됨
rollingInterval: RollingInterval.Day, // 매일 새로운 파일 생성
outputTemplate: “{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}” // 로그 형식 지정
)
);

 

if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(“/Home/Error”);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
name: “default”,
pattern: “{controller=Home}/{action=Index}/{id?}”);

app.MapRazorPages();

app.Run();

 

 

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
name: “default”,
pattern: “{controller=Home}/{action=Index}/{id?}”);

app.MapRazorPages();

app.Run();

Posted by