'2017/12'에 해당되는 글 4건

Programming/.NET

사용자에게 특정 내용을 표현해서 보여주고자 할때 변수의 이름을 그대로 출력해야 하는 경우가 있습니다.

 

string Name = "guest";

Console.WriteLine($"Hello! Your Name : {Name}");

 

위 예제에서 Name이 그러한 경우인데 이처럼 단순 문자열로 표현해도 되지만 특별히 nameof를 사용해서 표현할 수도 있습니다.

 

string Name = "guest";

Console.WriteLine($"Hello! Your {nameof(Name)} : {Name}");

 

굳이 변수명을 이렇게 할 이유는 혹시라도 변수명이 바뀌었을때 오류를 발생시켜 항상 변수의 이름을 정확히 표현할 수 있도록 하기 위함입니다. 변수명을 단순히 문자열로 표현해 버리면 컴파일과정에서 변수명이 바뀌었는지 확인이 안되므로 변수명과 문자열내용이 일치하지 않는 상황이 생길 수 있기 때문입니다.

 

'Programming > .NET' 카테고리의 다른 글

[C#] EventWaitHandle  (0) 2018.01.16
[ASP.NET MVC] 번들(Bundle)  (0) 2018.01.02
[C#] nameof  (0) 2017.12.27
[ASP.NET MVC] AJAX  (0) 2017.12.22
[C#] Assembly  (0) 2017.12.13
[C#] LINQ  (0) 2017.12.05
0 0
Programming/.NET

AJAX를 따로 구현하지 않고 만들어진 일반적인 경우는 서버로 부터 특정 페이지의 모든 컨텐츠를 내려받아 화면에 표시하는 방법이 될것입니다.

 

public class Member
{
    public string Name { getset}

    public string Email { getset}

    public DateTime BirthDay { getset}
    public int Point { getset}

    public MemberType MT { getset}
}

public enum MemberType
{
    Admin,
    Normal,
    Guest
}

▶ Model

 

public class HomeController : Controller
{
    Member[] mb = {
        new Member() { Name = "홍길동"Email = "hong1@cliel.com"Point = 100, BirthDay = new DateTime(1981, 11, 14)MT = MemberType.Guest },
        new Member() { Name = "홍길남"Email = "hong2@cliel.com"Point = 110, BirthDay = new DateTime(1980, 4, 23)MT = MemberType.Admin },
        new Member() { Name = "홍길석"Email = "hong3@cliel.com"Point = 55, BirthDay = new DateTime(1973, 8, 19)MT = MemberType.Normal },
        new Member() { Name = "홍길순"Email = "hong4@cliel.com"Point = 80, BirthDay = new DateTime(1992, 6, 5)MT = MemberType.Normal },
        new Member() { Name = "홍길영"Email = "hong5@cliel.com"Point = 98, BirthDay = new DateTime(1986, 3, 8)MT = MemberType.Normal }
    };

    // GET: Home
    public ActionResult Index()
    {
        return View(mb);
    }

    [HttpPost]
    public ActionResult Index(string mt)
    {
        if (string.IsNullOrEmpty(mt))
            return View(mb);
        else {
            MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
            return View(mb.Where(x => x.MT == MT));
        }
    }
}

▶ Controller

 

@using WebApplication1.Classes
@model IEnumerable<WebApplication1.Classes.Member>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
        <table border="1">
            <thead><tr><th>이름</th><th>포인트</th><th>생년월일</th></tr></thead>
            @foreach (Member m in Model) {
                <tr>
                    <td>@m.Name</td>
                    <td>@m.Point</td>
                    <td>@m.BirthDay.ToString("yyyy년MM월dd일")</td>
                </tr>
            }
        </table>
    </div>
    <br />
    @using (Html.BeginForm()) {
        @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
        <input type="submit" value="확인" />
    }
</body>
</html>

▶ Index View

 

이 예제는 AJAX없는 일반적인 방법으로 View의 DropDownList로 표시된 항목중 원하는 항목을 선택하고 '확인'버튼을 누르면 HttpPost속성이 설정된 액션메서드로 선택한 타입이 전달되어 Where확장메서드를 통해 필터링된 Member의 리스트를 표시합니다. 여기서 주목해야할 부분은 Member의 리스트를 다시 받아오는 방식인데 현재는 View에 존재하는 모든 컨텐츠를 일괄적으로 받아오고 있습니다.

 

컨텐츠의 양이 작아 사실 이정도 트래픽이 발생하는 것은 부담스러운게 아니지만 View에 이미지나 CSS, JAVA Script파일등이 같이 존재하는 페이지면 단순히 명단을 불러오기위해 페이지 전체를 새로고침하게 되고, 이는 모든 컨텐츠를 처음부터 새로 받아와야 하는 비효휼적인 동작방식으로 연결됩니다.

 

이런 문제를 해결하기 위한 방법중 하나로 우리는 AJAX를 사용할 수 있습니다. AJAX는 Asynchronous JavaScript and XML로서 비동기로 서버와 통신해 필요한 내용만을 XML포멧으로 수신하여 웹페이지에 반영하는 기술입니다. 이것은 페이지의 새로고침을 유도하지 않고 페이지상에 필요한 부분만을 바꿀 수 있는 방법이 됩니다.

 

웹프로그램에 AJAX를 구현하려면 우선 NuGet 패키지 관리자를 통해 JQuery와 Microsoft.Jquery.Unobtrusive.Ajax 패키지를 설치해야 합니다.

 

 

패키지를 설치하고 나면 프로젝트의 Script 폴더에 몇가지 스크립트 파일이 추가되는데 이중에서 2가지 스크립트를 AJAX구현이 필요한 페이지에 다음과 같이 추가하도록 합니다.

 

<head>

    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-3.1.1.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>

 

그런다음 본래 데이터를 받아오는 액션메서드를 자식액션메서드로 수정하여 데이터처리를 자식액션메서드에서 처리할 수 있도록 합니다.

 

public PartialViewResult GetMember(string mt)
{
    if (string.IsNullOrEmpty(mt))
        return PartialView(mb);
    else {
        MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
        return PartialView(mb.Where(x => x.MT == MT));
    }
}

 

그리고 기존 Index 액션메서드를 수정해야 하는데 이는 Index View에서 더이상 Member의 열거타입에 대한 처리를 수행하고 있지 않기에 부분뷰로 필터링할 문자열넘 넘겨주는 구조가 되어야 하기 때문입니다.

 

public ActionResult Index()
{
    return View((object)string.Empty);
}

 

그런다음 자식액션에 맞는 부분뷰를 만들어 기존에 Index뷰에 있던 foreach부분을 그대로 옮겨놓습니다.

 

@using WebApplication1.Classes
@model IEnumerable<WebApplication1.Classes.Member>

@foreach (Member m in Model) {
    <tr>
        <td>@m.Name</td>
        <td>@m.Point</td>
        <td>@m.BirthDay.ToString("yyyy년MM월dd일")</td>
    </tr>
}

▶ GetMember.cshtml 부분뷰

 

Member를 표시하는 부분을 부분뷰로 이동시키고 나면 기존의 Index뷰에서는 기존 표시부분을 부분뷰로 대체할 수 있도록 다음과 같이 변경해야 합니다.

 

@using WebApplication1.Classes
@model string

@{
    Layout = null;

    AjaxOptions ao = new AjaxOptions { UpdateTargetId = "memberBody" };
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-3.1.1.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>
<body>
    <div>
        <table border="1">
            <thead><tr><th>이름</th><th>포인트</th><th>생년월일</th></tr></thead>
            <tbody id="memberBody">
                @Html.Action("GetMember"new { mt = Model })
            </tbody>
        </table>
    </div>
    <br />
    @using (Ajax.BeginForm("Getmember", ao)) {
        @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
        <input type="submit" value="확인" />
    }
</body>
</html>

 

본문에 foreach로 Member를 표시하는 부분을 자식뷰를 통해 가져올 수 있도록 하였습니다. 또한 기존 Html.BeginFrom을 Ajax로 대체하여 DropDonList의 선택항목을 자식액션메서드인 GetMember로 전송하게 하고 AjaxOptions 의 인스턴스를 함께 전달하고 있습니다.

 

따라서 DropDownList 에서 원하는 항목을 선택하고 폼을 제출하는 버튼인 '확인'을 누르면 서버측에 데이터를 요청하고 그 결과를 화면의 새로고침이 없이 즉각적으로 갱신할 것입니다. 만약 버튼대신 특정 링크를 통해 AJAX동작을 수행하고자 한다면 BeginForm대신 ActionLink 메서드를 통해 다음과 같이 링크를 생성할 수 있습니다.

 

@Ajax.ActionLink("Guest""GetMember"new { mt = "Guest" }, ao)

 

AjaxOptions는 또한 여러 속성을 지정하여 AJAX동작을 수행할때 필요한 다양한 설정을 동반할 수 있습니다. 예를 들어 Confirm은 AJAX동작을 수행하기전 사용자에게 확인메세지를 표시하는 용도로 사용될 수 있으며 UpdateTargetId 는 서버로 부터 수신된 내용을 표시할 HTML영역에 대한 ID를 지정할 수 있습니다.

 

@{
    Layout = null;

    AjaxOptions ao = new AjaxOptions { UpdateTargetId = "memberBody"Confirm = "Memer를 불러 오시겠습니까?" };
}

 

이렇게 AJAX를 구현하고 나면 페이지를 새로고침하지 않고도 표현된 데이터를 갱신할 수 있게 되었습니다. 그런데 만약 요청하려는 데이터를 가져오기까지 시간이 많이 걸리는 경우 사용자 입장에서는 그냥 화면이 정지해 있는 상태로 보여질 수 있기 때문에 서버측에 데이터를 요청하면 화면이 갱신되기 까지 적절한 메세지를 표시할 필요가 있을 것입니다.

 

이를 위해 우선 사용자에게 필요한 메세지 영역을 만들고

 

<body>

    <div id="loading" style="display:none">
        기다려 주십시오.
    </div>
    <div>
        <table border="1">
            <thead><tr><th>이름</th><th>포인트</th><th>생년월일</th></tr></thead>
            <tbody id="memberBody">
                @Html.Action("GetMember"new { mt = Model })
            </tbody>
        </table>
    </div>
    <br />
    @using (Ajax.BeginForm("GetMember", ao)) {
        @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
        <input type="submit" value="확인" />
    }
</body>

 

AjaxOptions 개체의 속성을 다음과 같이 설정합니다.

 

AjaxOptions ao = new AjaxOptions { UpdateTargetId = "memberBody"Confirm = "Memer를 불러 오시겠습니까?"LoadingElementId="loading"LoadingElementDuration=1000 };

 

LoadingElementId 는 메세지 영역을 만들어둔 html 요소의 id값을 지정하며 LoadingElementDuration 에는 해당 영역이 애니메시션형식으로 표시될 시간을 지정합니다. 이렇게 하면 서버에 데이터를 요청할때마다 메세지가 존재하는 div영역이 1초간 서서히 화면에 표시될 수 있습니다.

 

AJAX를 통해 서버에 데이터를 요청하고 응답된 데이터를 가져와 화면에 갱신시키는 과정에서 필요하다면 콜백메서드를 활용해 특정 처리를 수행할 수도 있습니다. 예를 들어 작업이 완료된 경우 사용자에게 '완료'라는 메세지를 보여주고 싶다면 아마도 다음과 같이 처리할 수 있을 것입니다.

 

<script type="text/javascript">
    var OnComplete = function (req, status) {

            alert('완료됨');
        };
</script>

 

우선 위와 같이 콜백으로 호출될 메서드를 생성하고

 

AjaxOptions ao = new AjaxOptions
{
    UpdateTargetId = "memberBody",
    LoadingElementId = "loading",
    LoadingElementDuration = 1000,
    OnComplete = "OnComplete"
};

 

해당 메서드를 AjaxOptions 개체에 설정하면 모든 작업이 완료되었을때 OnComplete 메서드를 자동으로 호출할 것입니다. 이 외에도 처리시작전 호출되는 메서드는 OnBegin, 작업실패시 호출되는 메서드는 OnFailure, 작업성공시 호출되는 메서드는 OnSuccess 속성을 통해 설정하면 됩니다.

 

특히 OnSuccess 메서드는 매개변수로 서버로부터 응답되어 오는 데이터를 받을 수 있는데 이를 이용하면 AJAX의 응답을 JSON으로 처리하려고 할때 해당 데이터를 적절히 처리할 수 있는 방안을 제공합니다.

 

public JsonResult GetMemberJson(string mt)
{
    if (string.IsNullOrEmpty(mt))
        return Json(mb);
    else
    {
        MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
        return Json(mb.Where(x => x.MT == MT));
    }
}

 

서버로 부터의 결과를 JSON으로 받고자 한다면 우선 JsonResult 형식을 반환하는 액션메서드를 생성해야 합니다. 또한 액션 메서드는 내부에서의 반환을 Json메서드로 처리하여 데이터를 JSON 포멧으로 반환할 수 있도록 처리합니다.

 

@using (Ajax.BeginForm("GetMemberJson", ao)) {
    @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
    <input type="submit" value="확인" />
}

 

그런 다음 Form에서의 데이터 요청이 위에서 작성한 GetMemberJson으로 갈 수 있도록 하고

 

<script type="text/javascript">
    var OnSuccess = function (data) {
        $('#memberBody').empty();

        for (var i = 0; i < data.length; i++) {
            var date = new Date(parseInt(data[i].BirthDay.substr(6)));
            $('#memberBody').append('<tr><td>' + data[i].Name + '</td><td>' + data[i].Point + '</td><td>' + date.getFullYear() + '년' + date.getMonth() + '월' + date.getDay() + '일' + '</td></tr>');
        }
    };
</script>

 

OnSuccess 메서드에서 data를 인자로 받아 이전과 동일하게 보여질 수 있도록 스크립트를 통해 처리합니다. 이때 data는 JSON포멧형태로 반환되어 오는 데이터가 될것입니다.

 

AjaxOptions ao = new AjaxOptions
{
    UpdateTargetId = "memberBody",
    LoadingElementId = "loading",
    LoadingElementDuration = 1000,
    OnSuccess = "OnSuccess"
};

 

그리고 AjaxOptions 개체에 OnSuccess 메서드를 지정하면 JSON으로 데이터 포멧을 다룰 수 있는 모든 처리가 완료됩니다.

 

하지만 스크립트를 통해서 데이터를 처리하다보니 다소 코드가 장황해지는 상황이 발생할 수 있는데 예제에서는 Member의 BirthDay를 처리하기 위해 getFullYear나 getMonth처럼 각 날짜에 해당하는 메서드를 일일이 호출하여 날짜형식의 포멧을 맞추려고 하고 있습니다. 물론 굳이 이렇게 하지 않아도 되지만 이런 형태의 장황함은 얼마든지 존재할 수 있으며 이러한 문제는 액션메서드에서 다음과 같이 필요한 필드의 포멧을 맞추어 줌으로서 해결할 수 있습니다.

 

public JsonResult GetMemberJson(string mt)
{
    if (string.IsNullOrEmpty(mt))
        return Json(mb);
    else
    {
        MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
        return Json(mb.Where(x => x.MT == MT).Select(x => new { Name = x.NamePoint = x.PointBirthDay = x.BirthDay.ToString("yyyy년MM월dd일") }));
    }
}

 

참고로 예제에서는 UpdateTargetId 속성이 여전히 존재하는데 이 속성은 수정된 현재의 상황에는 필요없는 속성이므로 제거되어도 프로그램에는 아무런 영향을 끼치지 않습니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET MVC] 번들(Bundle)  (0) 2018.01.02
[C#] nameof  (0) 2017.12.27
[ASP.NET MVC] AJAX  (0) 2017.12.22
[C#] Assembly  (0) 2017.12.13
[C#] LINQ  (0) 2017.12.05
[C#] 문자열 보간 ($)  (0) 2017.11.28
0 0
Programming/.NET

System.Reflection.Assembly를 이용하면 어셈블리(DLL)의 직접적인 참조없이 동적으로 DLL을 로드하고 사용할 수 있습니다. 이 방법을 살펴보기 전에 아래와 같이 간단한 DLL을 만들어 보겠습니다.

 

namespace myDll
{
    public class Class1
    {
        public Class1()
        { }

        public object myCal(int i, int j)
        {
            return i + j;
        }
    }
}

 

이를 컴파일하면 myDll.dll이 생성된다고 가정해 보겠습니다.

 

Assembly asm = Assembly.LoadFrom(@"C:\Users\testuser\Documents\Visual Studio 2015\Projects\test\myDll\bin\Debug\myDll.dll");
Type t = asm.GetType("myDll.Class1");

 

우선 Assembly의 LoadFrom 메서드를 통해 로드할 어셈를리(DLL)의 위치를 잡아주고 GetType으로 어셈블리 타입정보를 추출하도록 합니다.

 

ConstructorInfo ci = t.GetConstructor(Type.EmptyTypes);
object oci = ci.Invoke(null);

 

Type의 GetConstructor 메소드에서 Type.EmptyTypes를 지정하면 해당 타입의 기본생성자를 반환하며 Constructorinfo에서 invoke를 통해 반환받은 생성자를 호출하여 타입의 객체를 생성하게 됩니다.

 

MethodInfo mi = t.GetMethod("myCal");

object[] i = new object[2];
i[0] = 10;
i[1] = 20;

object r = mi.Invoke(oci, i);

 

객체가 생성되었으니 이제 메서드등의 타입을 호출할 수 있습니다. 위에서는 GetMethod를 통해 myCal을 지정하여 해당 메소드타입을 가져올 수 있도록 하였습니다. invoke는 지정된 메서드를 호출하기 위함인데 만약 메서드에 매개변수를 전달해야 한다면 invoke의 두번째 인자로 필요한만큼의 배열을 생성하여 전달하면 됩니다. invoke호출시 따로 매개변수 전달이 필요없다면 null을 지정합니다.

 

위와 같이 Assembly를 활용한다면 꽤 덩치가 큰 솔루션을 개발할때 사용자가 필요한 기능을 직접 개발하도록 하고 이를 확장프로그램형식으로 활용할 수 있는 방안을 제공할 수 있습니다. 이는 엑셀이나 워드같은 프로그램에서 사용자 정의된 기능이 필요할때 이를 확장프로그램형식으로 탑재하고 사용할 수 있도록 하는 것이나 크롬이나 익스플로러같은 웹브라우저에서 직접 사용자 정의 프로그램을 만들 수 있도록 하는것과같은 방식의 구현이 가능함을 의미합니다.

'Programming > .NET' 카테고리의 다른 글

[C#] nameof  (0) 2017.12.27
[ASP.NET MVC] AJAX  (0) 2017.12.22
[C#] Assembly  (0) 2017.12.13
[C#] LINQ  (0) 2017.12.05
[C#] 문자열 보간 ($)  (0) 2017.11.28
[C#] ArrayList  (0) 2017.11.14
0 0
Programming/.NET

배열이나 컬렉션에 들어간 요소를 순회하는 고전적인 방법중 하나는 foreach를 이용하는 것입니다.

 

List<Member> li = new List<Member{
    new Member { Name = "홍길동"Age = 40, BirthDay=DateTime.Parse("1978-01-28") },
    new Member { Name = "홍길순"Age = 21, BirthDay=DateTime.Parse("1997-05-16") },
    new Member { Name = "홍길남"Age = 38, BirthDay=DateTime.Parse("1980-03-06") },
    new Member { Name = "홍길영"Age = 19, BirthDay=DateTime.Parse("1999-11-20") },
    new Member { Name = "홍길석"Age = 27, BirthDay=DateTime.Parse("2003-08-04") }
};

foreach (Member m in li) {
    Console.WriteLine(m.Name);
}

 

이 상태에서 만약 나이가 20세 이상인 사람만을 추려내려면 if문을 추가할 수 있을 것입니다.

 

foreach (Member m in li) {
    if (m.Age > 20)
        Console.WriteLine(m.Name);
}

 

LINQ(Language Integrated Query)는 이러한 열거작업에 대한 확장구문으로서 SQL 쿼리와 비슷한 문법체계를 가지고 있습니다. 여기에서는 예제로 LIst형식의 컬렉션만을 다루고 있지만 컬렉션뿐만 아니라 XML이나 DB와의 연동에서도 LINQ가 사용되고 있습니다. 이렇게 다양한 곳에서 LINQ가 사용된다는 것은 LINQ문법만 익히면 일관된 방식으로 데이터를 쿼리할 수 있다는 것을 뜻합니다.

 

우선 간단하게 LINQ를 통해 전체를 열거하는 부분부터 살펴보겠습니다.

 

var ret = from Member in li
            select Member;

foreach (Member m in ret)
        Console.WriteLine(m.Name);

 

LINQ에서 select는 yield return과 같습니다. yield return은 IEnumerable<T>형식을 반환하므로 var ret는 IEnumerable<Member> ret로 바뀔 수 있습니다.

 

예제에서는 foreach에서 Name값을 가져오는데 이는 LINQ의 select에서도 처리될 수 있습니다.

 

var ret = from Member in li
            select Member.Name;

foreach (string m in ret)
        Console.WriteLine(m);

 

출력되는 값에 특정 포멧을 적용해야 한다면 select에서 익명타입을 구현하면 됩니다.

 

var ret = from Member in li
            select new { Name = Member.Name, BirthDay = Member.BirthDay.ToString("yyyy년MM월dd일") };

foreach (var m in ret)
        Console.WriteLine(m.Name + " : " + m.BirthDay);

 

LINQ에서 where를 이용하면 조건을 필터링할 수 있습니다.  여기에는 bool형식의 구문이 와야 합니다.

 

var ret = from Member in li
          where Member.Age > 20
          select Member;

foreach (var m in ret)
        Console.WriteLine(m.Name + " : " + m.BirthDay);

 

요소를 정렬하기 위해서는 orderby를 사용하며 IComparable 인터페이스가 구현된 타입이어야 합니다.

 

var ret = from Member in li
            orderby Member.Name descending
            select Member;

foreach (var m in ret)
        Console.WriteLine(m.Name);

 

orderby에서 descending는 내림차순, ascending는 오름차순입니다.

 

이외에도 서로 다른 컬렉션을 연결하는 join이나 특정 값으로 그룹핑하는 group by절등 다양한 구문이 존재하는데 여기서 몇몇 특징적인 기능의 경우에는 IEnumerable<T>의 확장메서드형태로 제공하는 것들이 있습니다.

 

예들 들면 select같은 경우

 

IEnumerable<Member> im = li.Select((em) => em);
foreach (Member m in im)
    Console.WriteLine(m.Name);

 

위와 같은 형태로 구현할 수 있도록 되어 있는데, 이러한 확장 메서드는 Select외에 Where나 OrderBy등 수십여가지의 메서드가 존재하니 필요할때 적절한 메서드를 사용하면 됩니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET MVC] AJAX  (0) 2017.12.22
[C#] Assembly  (0) 2017.12.13
[C#] LINQ  (0) 2017.12.05
[C#] 문자열 보간 ($)  (0) 2017.11.28
[C#] ArrayList  (0) 2017.11.14
[C#] 선택적 매개변수  (0) 2017.11.07
0 0
1
블로그 이미지

클리엘