| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- 작업 2유형
- 네트워크 면접 답변
- 빅분기 캐글놀이터
- 빅분기 1유형
- 주말에도 1일 1쿼리
- 빅분기
- .NET Razor
- .NET 프레임워크 기초
- 작업 1유형
- 빅분기 판다스 100제
- .NET 게시판 프로젝트
- SQL
- 빅데이터 분석기사
- MySQL
- 1일 1쿼리
- 모델 학습 및 예측
- SpringBoot와 .NET의 차이점
- 빅분기 필기 pdf
- MAUI Board
- sqld 시험 정리
- 운영체제 면접 답변
- Xamarin Maui
- 컴포지션과 집합
- mysql mongo 성능 비교
- rdbms nosql 차이
- Mac OS .NET 개발환경
- MAUI 학습
- flutter 믹스인
- 주말도 한다
- FLUTTER
- Today
- Total
subindev 개발 블로그
[C#] 3. ToDo & 회원 가입 - ASP.NET & EF CORE (Oracle연동) 본문
📝 [개발일지] ASP.NET Core Todo 프로젝트 2025/12/02(화)
ASP.NET Core + Oracle + EF Core 조합으로
Todo List 기능을 만들며 여러 오류를 해결하고,
C#/.NET 문법 특징도 함께 정리한 하루였다.
오늘 .Net 개발을 하며 겪은 다양한 오류 상황을 기록하려고 한다
다음에도 참고하기 위해 정리해둔다.
📌 1. 오늘 작업 요약
✔ .NET + EF CORE (ORACLE 연동) 투두리스트 만들기
✔ 로그인, ToDoList 기능 만들기
✔ Oracle CHAR 타입 때문에 WHERE 절이 동작하지 않는 문제 해결
✔ Oracle PK 중복(ORA-00001) 오류 해결
✔ 로그인 후 사용자 Claim 값 가져오기 문제 해결
✔ Todo 추가/토글/삭제 로직을 AJAX 기반으로 재구성
✔ C#/.NET 문법 특징 정리 (Java와 비교하며 이해)
✔ Razor(View) + Controller 구조 흐름 이해
📌 2. Oracle CHAR 공백 문제 — WHERE 절이 왜 안될까?
❗ 문제
DB의 WRITER_ID가 CHAR(50) 이라서
값이 '104286 ' 처럼 우측 공백을 포함함.
그래서 다음 LINQ가 제대로 동작하지 않았다:
둘 다 문자열 같아 보여도
DB CHAR는 오른쪽에 공백이 붙어 있다.
✔ 해결 방법: Trim() 적용
Oracle 로그에서도 이렇게 변환된 걸 확인했다:
📌 Oracle에서 CHAR 쓰면 무조건 Trim 필요!
→ 나중에 테이블 수정 시 VARCHAR2로 바꾸는 것이 권장된다.
📌 3. ORA-00001 오류 — PK 중복 문제 해결
Todo 추가 시 다음 오류 발생:
❗ 원인
Oracle은 MySQL처럼 AUTO_INCREMENT가 없는데
ID 컬럼이 자동 증가가 아니었음.
EF Core가 삽입할 때 ID=0 을 계속 넣어서 PK 충돌.
✔ 해결
테이블의 ID 컬럼을 Identity로 지정:
이후 INSERT 시 Oracle이 자동으로 PK 값을 생성하여 해결됨.
📌 4. 로그인한 사용자 정보 가져오기 문제 해결
처음에는 Claim Key를 잘못 써서
아이디/이름이 null 또는 빈 값이 나왔다.
예: User.FindFirst("UserName") 를 읽으려 했지만
실제 저장한 Claim Key는 "QM05NAME" 이었다.
✔ 해결
📌 Claim Key는 로그인 시 설정한 이름 그대로 읽어야 한다.
📌 5. Todo 로직을 AJAX 기반으로 개선
기존 구조는 다음과 같았다:
- 추가(Add) → POST → Index Redirect
- 토글(Toggle) → GET → DB 수정 → Redirect
- 삭제(Delete) → GET → DB 삭제 → Redirect
➡ 모든 요청이 페이지 이동 기반이라 좋지 않았다.
✔ 해결: 모두 AJAX 기반으로 변경
(1) Todo 추가 AJAX
(2) 완료 체크(Toggle) AJAX
(3) 삭제 AJAX
➡ 화면 이동 없이 자연스럽게 동작
➡ 컨트롤러 로직은 완전히 분리
(Index는 조회만 담당)
📌 6. C# / .NET 문법 특징 정리
오늘 작업하다 자연스레 다시 느낀 C#/.NET 문법 특징을 정리해본다.
✔ 1) C#은 PascalCase를 사용함
- 클래스명 → PascalCase
- 메서드명 → PascalCase
- Property → PascalCase
예:
Java의 camelCase와 다름.
✔ 2) Entity 속성은 기본적으로 null 허용 X
C#의 string은 참조 타입이라 null 가능하지만,
EF Core는 Required 붙이면 자동 검증됨.
✔ 3) new로 객체 생성 시 초기화 가능
✔ 4) Controller에서 return 종류
- return View(model) : 화면 렌더링
- return RedirectToAction("Index") : 이동
- return Ok() : 200 OK
- return BadRequest() : 400
- return NotFound() : 404
✔ 5) .NET Authentication 흐름
- 로그인 성공 → ClaimsIdentity 생성
- CookieAuth로 사용자 정보 저장
- User.FindFirst() 로 어디서든 읽기 가능
✔ 6) Razor 문법
- @variable
- @{ ... }
- @if(...){}
- @model List<T> ← 중요
HTML과 C#이 섞이는 문법.
✔ 7) Authentication - 쿠키 저장 방식 (SSR 방식)
// Program.cs
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Login"; // 로그인 페이지
options.LogoutPath = "/Account/Logout"; // 로그아웃
options.ExpireTimeSpan = TimeSpan.FromHours(4); // 쿠키 유지시간
});
builder.Services.AddAuthorization();
app.UseAuthentication(); // 반드시 UseAuthorization(); 앞에 존재해야함
app.UseAuthorization();
// AccountController.cs
// -----------------------------------------------------
// 로그인 처리 (POST)
// -----------------------------------------------------
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
// 유효성 검사 실패 시
if (!ModelState.IsValid)
{
return View(model);
}
_logger.LogInformation("로그인 시도 - ID: {Id}", model.QM05IPID);
// 사용자 조회
var user = _context.Users
.FirstOrDefault(u =>
u.QM05IPID.Trim() == model.QM05IPID.Trim() &&
u.QM05PSWD.Trim() == model.QM05PSWD.Trim());
// Oracle char 과 C# string을 비교할 대 Trim 이 없다면 에러 발생
// Oracle char(8) 이라면 '125641 ' 으로 저장되어 있기 때문
if (user == null)
{
// 로그인 실패 메시지 전달
ViewBag.Error = "아이디 또는 비밀번호가 올바르지 않습니다.";
return View(model);
}
// 로그인 성공 → 인증 정보 쿠키에 저장
var claims = new List<Claim>
{
new Claim("QM05IPID", user.QM05IPID),
new Claim("QM05NAME", user.QM05NAME)
};
_logger.LogInformation("User 정보: {user}", user);
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
principal);
return RedirectToAction("Todo", "Todo");
}
// AccountController.cs
// -----------------------------------------------------
// TODO : 로그아웃 처리 (POST)
// -----------------------------------------------------
[HttpPost]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync(); // 쿠키에서 로그인 정보 삭제
return RedirectToAction("Login", "Account");
}
인증된 사용자 정보 사용 방법
// TodoController.cs
public IActionResult Todo()
{
try
{
// 로그인
var userId = User.FindFirst("QM05IPID")?.Value;
var userName = User.FindFirst("QM05NAME")?.Value;
List<TodoViewModel> list = _context.TodoItems
.Where(t => t.Writer.Trim() == userId.Trim())
.OrderByDescending(t => t.Id)
.Select(t => new TodoViewModel
{
Id = t.Id,
Writer = t.Writer,
Content = t.Content,
IsDone = t.IsDone,
CreatedAt = t.CreatedAt
})
.ToList();
return View(list);
}
catch (Exception e)
{
_logger.LogError(e, "TODO Controller - TODO 조회 중 오류 발생");
return StatusCode(500, new { message = "서버 오류가 발생했습니다." });
}
}
📌 7. 마무리

오늘은 처음엔 단순한 Todo 기능처럼 보였지만,
중간중간 발생한 문제들이 실제로 굉장히 중요한 개념들이었다.
- Oracle DB 타입 차이
- PK 자동 증가 문제
- Razor + MVC + AJAX 조합
- java와 C# 문법 차이
- Controller 책임 분리
이런 것들을 한 번에 경험하면서
.NET 기반 웹 개발의 전반적인 흐름을 더 깊게 이해하게 된 하루였다.
다음에 이 글을 다시 보면
오늘 어떤 문제 해결 과정을 거쳤고
왜 이런 방식으로 구조가 되었는지 빠르게 떠올릴 수 있을 것이다.
'.NET' 카테고리의 다른 글
| [.NET] 2. ASP.NET Core MVC + MySQL 게시판 프로젝트 (VS Code) (0) | 2025.10.15 |
|---|