개발

.NET에서 Excel 생성

.NET에서 Excel 생성하는 좋은 방법이 무엇이 있을까?

가장 먼저 떠오르는 것은 HTML 식으로 생성하는 방법이다.

두 번째로 XML을 사용하여 생성하는 방법이다.

세 번째로는 미리 Excel 파일을 생성한 후 OleDB를 사용하여 로드하여 쓰는 것이다.

첫 번째, 두 번째 방법은 호환성 문제가 있다.

아무래도 바이너리 파일이 아니다 보니 제대로 인지 못하는 경우가 있다.

세 번째 방법은 시스템을 타는 현상이 나타났다.

개발서버에서는 정상으로 동작하는 실 서버에서는 제대로 동작을 하지 않는 문제가 있었다.

실 서버가 해외의 경우에는 문제 해결에 시간이 많이 소요된다.

이번에 찾은 다른 방법은 MyXLS 라이브러리를 사용하는 것이다.

MyXLS

사이트: http://sourceforge.net/projects/myxls/

Java에서 Excel 만드는 것과 비슷하게 프로그래밍 방식으로 Excel 파일을 만든다.

이것에 단점은 Excel 로드에 문제가 있다는 것이다.

여러 가지 기능이 지원되지만 간단한 쓰기만 테스트해 보았다.

다음은 사용 예이다.

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import Namespace="org.in2bits.MyXls" %>
<script runat="server">
void Page_Load(object sender, EventArgs e) {
    try {
        XlsDocument xls = new XlsDocument();
        xls.FileName = "story_" + DateTime.Now.ToString("yyyy-MM-dd_HH_mm") + ".xls";
        xls.SummaryInformation.CodePage = 2;
        xls.SummaryInformation.Author = "Barney Kim";
        xls.SummaryInformation.Title = "Excel Write Test";
        xls.SummaryInformation.Subject = "Test";
        xls.SummaryInformation.Comments = ""; // To remove default value
        xls.DocumentSummaryInformation.Company = "barney.PE.kr";
        int sheetCount = 0;
        int rowCount = 1;
        int colCount = 1;
        Worksheet sheet = null;
        for(int i=0; i < 70000; i++) {
            Cells cells = null;
            if (rowCount == 1) {
                if (sheetCount == 1) {
                    sheet = xls.Workbook.Worksheets.AddNamed("Shee");
                } else {
                    sheet = xls.Workbook.Worksheets.AddNamed("Sheet" + sheetCount);
                }
                cells = sheet.Cells;
                cells.Merge(rowCount, rowCount, colCount, 7);
                Cell c = cells.Add(rowCount, colCount++, "My Excel Write Test");
                c.Font.Bold = true;
                c.Font.Height = 20 * 12;
                rowCount++;
                colCount = 1;
                //
                cells.Add(rowCount, colCount++, "No");
                cells.Add(rowCount, colCount++, "Name");
                cells.Add(rowCount, colCount++, "Email");
                cells.Add(rowCount, colCount++, "Title");
                cells.Add(rowCount, colCount++, "Date");
                cells.Add(rowCount, colCount++, "View Count");
                cells.Add(rowCount, colCount++, "IP Address");
                colCount = 1;
                rowCount++;
            } else {
                cells = sheet.Cells;
            }
            //
            cells.Add(rowCount, colCount++, i);
            cells.Add(rowCount, colCount++, "테스터");
            cells.Add(rowCount, colCount++, "some@some.com");
            cells.Add(rowCount, colCount++, "테스트라네");
            cells.Add(rowCount, colCount++, DateTime.Now.ToString("yyyy-MM-dd HH:mm"));
            cells.Add(rowCount, colCount++, 2);
            cells.Add(rowCount, colCount++, "127.0.0.1");
            rowCount++;
            colCount = 1;
            if (rowCount > 50003) {
                rowCount = 1;
                sheetCount++;
            }
        }
        xls.Send();
    } catch (Exception ex) {
        Response.Write("Error occurred");
    }
}
</script>

JSON 테스트

JSON 사이트를 보면 JSON에 대해 다음과 같이 설명하고 있다.

JSON(JavaScript Object Notation)은 경량의 데이터 교환 형식이다.

JSON은 두개의 구조로 되어있다.

  1. name/value 쌍으로 구성된 집합으로 object, record, struct, dictionary, hash table과 같다.
  2. 정렬된 값의 배열로 array, vector, list와 같다.

멜론의 앨범 수록곡, 네이버의 오픈캐스트등 실 사용 예는 많다.

특히 네이버의 오픈캐스트를 보면서 데이터를 자체적으로만 사용한다면 XML을 만들기보다 JSON을 사용하는 것이 좋다는 느낌을 받았다.

간단한 JSON 테스트를 해보면 다음과 같다.

json_test.html

<html>
<head>
<script type="text/javascript" src="/js/lib/prototype.js"></script>
<script type="text/javascript">
onload = function() {
    var url = "json_result.html";
    var params = "name=" + encodeURIComponent("테스트");
    var opts = {
        method : "post",
        parameters : params,
        onComplete : go_result
    }
    try {
        var req = new Ajax.Request(url, opts);
    } catch (e) {
        alert("Ajax Error=" + e);
    }
    return false;
}
function go_result(o) {
    try {
        var t = o.responseText;
        var j=t.evalJSON(true);
        alert("Result=" + j.message + "," + j.code);
    } catch(e) {
        alert("JSON Error=" + e);
    }
}
</script>

json_result.html

{
    "message":"성공",
    "code":200
}

Flash에서는 JSON 사이트에서 배포하는 JSON 클래스를 사용하여 다음과 같이 사용할 수 있다.

json_test.fla

import JSON;

var lv:LoadVars = new LoadVars();
lv.onData = function(src:String) {
    if(src != undefined) {
        trace(src);
        try {
            var json = new JSON();
            var o:Object = json.parse(src);
            trace("result=" + o.message);
        } catch (e) {
            trace(e.name + ":" + e.message + ":" + e.at + ":" + e.text);
        }
    }
}
lv.load("http://localhost/json_result.html");

ASP.NET UTF-8 상태에서 서울신용평가 실명 확인하기

ASP.NET에서는 보통 UTF-8 인코딩을 사용하여 작업하게 되지만,

서울신용평가 실명확인 서비스는 아직 UTF-8 인코딩을 지원하지 않는다.

이를 위해 EUC-KR로 만든 페이지를 통해 요청을 보내고 받는 편법을 사용할 수도 있다.

하지만 이것은 보통의 ASP.NET 사용과는 다르기때문에 마음에 들지 않는다.

이것은 다음과 같이 하여 문제를 처리할 수 있다.

또한 이 방법은 실명 확인 뿐 아니라 SMS 서비스와 같이 EUC-KR만 지원하는 각종 서비스를 이용하는 방법으로 사용할 수 있다.

<%@ Page Language="C#" ... %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="log4net" %>
<script runat="server">
// 로그
private static readonly ILog log = LogManager.GetLogger("Some.Web");
// 서울신용평가 실명확인 URL
private static readonly string SIREN24_URL = "https://name.siren24.com/servlet/name_check";
// 실명확인 요청하는 페이지
private static readonly string CHECK_URL = "http://some.com/check.aspx";
// 실명확인 결과 페이지
private static readonly string CHECK_RESULT = "http://some.com/check_result.aspx";
/// <summary>
/// 실명 확인하기 버튼 클릭
/// </summary>
void Submit_ServerClick(object sender, EventArgs e) {
    StringBuilder sb = new StringBuilder());
    sb.Append("id=SOMEID&");
    sb.Append("name=").Append(Name.Value).Append("&");
    sb.Append("jumin1=").Append(Jumin1.Value).Append("&");
    sb.Append("jumin2=").Append(Jumin2.Value).Append("&");
    sb.Append("ok_url=").Append(CHECK_RESULT);
    string result = CheckSiren24(SIREN24_URL, sb.ToString(), CHECK_URL);
    if(result == null) {
        // Error
    }
    ...
}
/// <summary>
/// 서울신용평가 실명확인
/// </summary>
///
/// <param name="url">서울신용평가 실명확인 URL</param>
/// <param name="parameters">매개변수</param>
/// <param name="referer">실명확인 URL을 요청하는 URL 정보</param>
///
/// <returns>실명확인 결과를 문자열로 반환한다. 실패하면 null</returns>
string CheckSiren24(string url, string parameters, string referer) {
    try {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
        req.Referer = referer;
        req.Method = WebRequestMethods.Http.Post;
        req.ContentType = "application/x-www-form-urlencoded";
        byte[] data = ToEucKr(parameters);
        req.ContentLength = data.Length;
        Stream stream = req.GetRequestStream();
        stream.Write(data, 0, data.Length);
        stream.Close();

        WebResponse res = req.GetResponse();
        StreamReader reader = new StreamReader(res.GetResponseStream(),
            Encoding.GetEncoding("EUC-KR")
        );
        string result = reader.ReadToEnd();
        reader.Close();
        return result;
    } catch(Exception ex) {
        log.Error("Exception=" + ex);
    }
    return null;
}
/// <summary>
/// 유니코드 문자열을 EUC-KR 인코딩 변환
/// </summary>
///
/// <param name="source">변환할 유니코드 문자열</param>
///
/// <returns>EUC-KR 인코딩된 바이트 배열</returns>
byte[] ToEucKr(string source) {
    byte[] b = Encoding.Unicode.GetBytes(source);
    return Encoding.Convert(Encoding.Unicode, Encoding.GetEncoding("EUC-KR"), b);
}
</script>
...
<form runat="server">
성명: <input type="text" id="Name" runat="server" ... /><br/>
주민번호: <input type="text" id="Jumin1" runat="server" .../>
<input type="text" id="Jumin2" runat="server" .../><br/>
<asp:ImageButton ID="BtnCheckJumin" OnClick="Submit_ServerClick" runat="server" ../>
</form>

서울 신용평가 실명 확인 결과는 다음과 같이 HTML로 되어있다.

<html>
<head>
<script language="JavaScript">
	function redirect(form)
	{
		form.submit();
	}
</script>
</head>
<body onLoad="JavaScript:redirect(document.target);">
	<form name=target method=post action="http://some.com/check_result.aspx">
		<input type=hidden name=jumin1 value="111111">
		<input type=hidden name=jumin2 value="1111111">
		<input type=hidden name=name value="홍길동">
		<input type=hidden name=result value="1">
	</form>
</body>
</html>

따라서 결과 문자열 중에 위의 굵게 표시된 result 값을 꺼내어 상태를 확인한다.