- MailService.cs 추가: ServiceBase 상속받는 Windows 서비스 클래스 - Program.cs 수정: 서비스/콘솔 모드 지원, 설치/제거 기능 추가 - 프로젝트 설정: System.ServiceProcess 참조 추가 - 배치 파일 추가: 서비스 설치/제거/콘솔실행 스크립트 주요 기능: - Windows 서비스로 백그라운드 실행 - 명령행 인수로 모드 선택 (-install, -uninstall, -console) - EventLog를 통한 서비스 로깅 - 안전한 서비스 시작/중지 처리 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
358 lines
13 KiB
C#
358 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Web.Http;
|
|
|
|
namespace Project.Web.Controllers
|
|
{
|
|
public class ReactController : ApiController
|
|
{
|
|
private string GetWwwRootPath()
|
|
{
|
|
// 실행 파일 기준으로 wwwroot 경로 찾기
|
|
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
|
var wwwrootPath = Path.Combine(baseDir, "Web", "wwwroot");
|
|
|
|
// 디버그 모드에서는 소스 경로 사용
|
|
if (!Directory.Exists(wwwrootPath))
|
|
{
|
|
wwwrootPath = Path.Combine(Directory.GetCurrentDirectory(), "Web", "wwwroot");
|
|
}
|
|
|
|
// 여전히 찾지 못하면 프로젝트 루트에서 찾기
|
|
if (!Directory.Exists(wwwrootPath))
|
|
{
|
|
var projectRoot = Directory.GetCurrentDirectory();
|
|
while (projectRoot != null && !Directory.Exists(Path.Combine(projectRoot, "Web", "wwwroot")))
|
|
{
|
|
projectRoot = Directory.GetParent(projectRoot)?.FullName;
|
|
}
|
|
if (projectRoot != null)
|
|
{
|
|
wwwrootPath = Path.Combine(projectRoot, "Web", "wwwroot");
|
|
}
|
|
}
|
|
|
|
return wwwrootPath;
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/test")]
|
|
public HttpResponseMessage Test()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-test.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React test file not found. Searched path: {filePath}. WWWRoot: {wwwrootPath}. Current Dir: {Directory.GetCurrentDirectory()}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React test page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/jsx-test")]
|
|
public HttpResponseMessage JsxTest()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-jsx-test.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "React JSX test file not found");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React JSX test page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/component/{filename}")]
|
|
public HttpResponseMessage Component(string filename)
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react", $"{filename}.jsx");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound, $"React component {filename} not found at {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/javascript");
|
|
|
|
// CORS 헤더 추가
|
|
response.Headers.Add("Access-Control-Allow-Origin", "*");
|
|
response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React component {filename}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/login")]
|
|
public HttpResponseMessage Login()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-login.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React login page not found. Searched path: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React login page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/dashboard")]
|
|
public HttpResponseMessage Dashboard()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-dashboard.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React dashboard page not found. Searched path: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React dashboard page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/common")]
|
|
public HttpResponseMessage Common()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-common.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React common page not found: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React common page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/jobreport")]
|
|
public HttpResponseMessage JobReport()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-jobreport.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React jobreport page not found: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React jobreport page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/kuntae")]
|
|
public HttpResponseMessage Kuntae()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-kuntae.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React kuntae page not found: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React kuntae page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/todo")]
|
|
public HttpResponseMessage Todo()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-todo.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React todo page not found: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React todo page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/project")]
|
|
public HttpResponseMessage Project()
|
|
{
|
|
try
|
|
{
|
|
var wwwrootPath = GetWwwRootPath();
|
|
var filePath = Path.Combine(wwwrootPath, "react-project.html");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
|
|
$"React project page not found: {filePath}");
|
|
}
|
|
|
|
var content = File.ReadAllText(filePath, Encoding.UTF8);
|
|
var response = Request.CreateResponse(HttpStatusCode.OK);
|
|
response.Content = new StringContent(content, Encoding.UTF8, "text/html");
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
|
|
$"Error serving React project page: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("react/status")]
|
|
public IHttpActionResult Status()
|
|
{
|
|
return Ok(new
|
|
{
|
|
status = "React Controller Active",
|
|
timestamp = DateTime.Now,
|
|
routes = new[]
|
|
{
|
|
"/react/test - React 기본 테스트 페이지",
|
|
"/react/jsx-test - React JSX 모듈화 테스트 페이지",
|
|
"/react/login - React 로그인 페이지",
|
|
"/react/dashboard - React 대시보드 페이지",
|
|
"/react/common - React 공용코드 페이지",
|
|
"/react/jobreport - React 업무일지 페이지",
|
|
"/react/kuntae - React 근태관리 페이지",
|
|
"/react/todo - React 할일관리 페이지",
|
|
"/react/project - React 프로젝트 페이지",
|
|
"/react/component/{filename} - JSX 컴포넌트 파일 서빙",
|
|
"/react/status - 이 상태 페이지"
|
|
}
|
|
});
|
|
}
|
|
}
|
|
} |