Assert.IsTrue(typeof(HomeController) .GetCustomAttributes(false) .Any(o => o.GetType() == typeof(AuthorizeAttribute)));
2012년 11월 22일 목요일
[ASP.NET MVC] 인증 필터 적용 여부 테스트
컨트롤러에 적용된 특성(Attribute)들은 리플렉션을 이용해 테스트하면 된다.
라벨:
ASP.NET MVC,
TDD
2012년 11월 21일 수요일
[ASP.NET MVC] 몇 가지 테스트 케이스들.
ViewResult
액션 메서드의 실행 결과는 ViewResult 클래스를 통해 테스트한다.[Test] public void Should_Load_Index_View() { var viewResult = new HomeController().Index() as ViewResult; // 뷰 이름 확인 Assert.AreEqual("Index", viewResult.ViewName); }
RedirectToRouteResult
POST 액션 메서드의 테스트는 모델 테스트를 포함한다. CRUD 작업 후 처리 방식에 따라 테스트 항목을 결정.[Test] public void Should_Delete_Item() { var deleteItem = Items.FindBy("id"); var redirectToRouteResult = (RedirectToRouteResult)new SampleController().Delete(deleteItem); // Item이 제대로 삭제되었는지 확인 Assert.IsFalse(Items.All.Contains(deleteItem)); // 삭제 후 Index 뷰가 표시됐는지 확인 Assert.AreEqual("Index", redirectToRouteResult.RouteValues["action"]); }
FormCollection
모델 바인딩을 사용할 수 없는 POST 액션 메서드는 FormCollection 클래스를 이용해 테스트.[Test] public void Should_Create_Item() { var item = new Item { Id = "1", Name = "Test Item" }; var formValues = new FormCollection(); formValues.Add("Id", item.Id); formValues.Add("Name", item.Name); var controller = new SampleController(); var result = controller.Create(formValues) as RedirectToRouteResult; Assert.IsTrue(Items.All.Contains(item)); Assert.AreEqual("Index", redirectToRouteResult.RouteValues["action"]); }
.
라벨:
ASP.NET MVC,
TDD
2012년 11월 20일 화요일
[iOS] UIWebView에서 자바스크립트 실행하기
stringByEvaluatingJavaScriptFromString 메시지를 이용하면 웹페이지의 자바스크립트 코드를 실행하고 반환값을 받을 수 있다. (스크립트)실행 시간이 10초를 넘으면 자동으로 실행 취소가 되며 nil을 반환하니 주의할 것.
// getLayoutStyle 스크립트 메서드를 실행한다. NSString* returnValue = [self.webView stringByEvaluatingJavaScriptFromString:@"getLayoutStyle"];
2012년 11월 15일 목요일
[iOS] UITableView의 바운스 및 스크롤 오류
UITableView와 UISearchBar를 동시에 사용하면 UITableView의 바운스와 스크롤이 안되는 경우가 있는데, 다음 코드를 viewDidLoad 메서드에 추가하면 해결할 수 있다.
self.tableView.bounces = YES;
참조
라벨:
Bounce,
iOS,
UISearchBar,
UITableView
[jQuery] XML 파싱
jQuery.parseXML() 메서드를 이용해 xml 문자열을 파싱한다.
$xml = $($.parseXML(xml)) $item = $xml.find("item:first"); alert($(item).text());
[ASP.NET MVC] 브라우저 캐시 회피하기
현재 개발 중인 모바일 버전 전자결재 서비스의 결재 시나리오다. 사용자가 [문서목록 페이지]에서 문서를 터치하면 [결재 페이지]가 표시된다. 결재 버튼을 터치하면 문서가 결재됐다는 알림과 함께 [문서목록 페이지]를 이동한다. 여기서 웹 브라우저의 'Back' 버튼이 문제가 된다. 'Back' 버튼을 누르면 이미 결재가 완료된 문서이기 때문에 한 단계 더 뒤로 가던가(history.back x 2), 결재가 완료된 문서에 접근했음을 알리는 알림이 필요하다. 우리는 간단히 알림을 제공하도록 [결재 페이지]의 최상단에 다음 스크립트를 입력했다.
하지만 결재 완료 후 'Back' 버튼을 누르면 스크립트는 무시되고 다시 [결재 페이지]가 표시된다. 이미 결재가 완료된 문서이기 때문에 결재, 반려 등의 UI가 표시되는건 문제가 된다. 스크립트가 무시되는 이유는 캐시 때문이다. 캐시에 저장된 웹 페이지가 스크립팅되지 않고 바로 표시되기 때문이다.
캐시 페이지가 아닌 Brand New 페이지를 표시하기 위해 [결재 페이지]의 액션 메서드에 다음 코드를 추가한다.
But.
크롬에서는 정상적으로 작동된다. 문제는 사파리였다. 실제 아이폰 애플리케이션에서는 위의 코드가 전혀 소용이 없다. 'Back' 버튼을 터치하면 캐시된 [결재 페이지]로 이동한다. 반나절을 구글과 StackOverflow를 해집고 돌아다니던 중 이유와 해결 방법을 찾았다. 최신 웹 브라우저들은(크롬은 되던데?) 일반적인 HTTP 캐시와는 차별되는Back/Foward를 위한 별도의 캐시를 제공한다. 이 때문에 위의 코드들이 사파리에서는 작동되지 않았던거다.
해결 방법은 '믿든지 말든지 (StackOverflow의 어느 개발자의 답글이었다. believe it or not.)' body 태그의 unload 이벤트에 빈 핸들러만 등록해주면 된다. 뭐 이런 경우가 있나 싶지만, 자~알 작동한다.이유는 참고 자료의 두 번째 링크를 통해 알 수 있다.
<% if (Model.IsApproved) { %> <script type="text/javascript"> alert("이미 결재가 완료된 문서입니다."); document.location.href = "/Approval/List"; </script> <%} %>
하지만 결재 완료 후 'Back' 버튼을 누르면 스크립트는 무시되고 다시 [결재 페이지]가 표시된다. 이미 결재가 완료된 문서이기 때문에 결재, 반려 등의 UI가 표시되는건 문제가 된다. 스크립트가 무시되는 이유는 캐시 때문이다. 캐시에 저장된 웹 페이지가 스크립팅되지 않고 바로 표시되기 때문이다.
캐시 페이지가 아닌 Brand New 페이지를 표시하기 위해 [결재 페이지]의 액션 메서드에 다음 코드를 추가한다.
// 캐시를 사용하지 않는다. Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache); Response.Cache.SetNoStore();
But.
크롬에서는 정상적으로 작동된다. 문제는 사파리였다. 실제 아이폰 애플리케이션에서는 위의 코드가 전혀 소용이 없다. 'Back' 버튼을 터치하면 캐시된 [결재 페이지]로 이동한다. 반나절을 구글과 StackOverflow를 해집고 돌아다니던 중 이유와 해결 방법을 찾았다. 최신 웹 브라우저들은(크롬은 되던데?) 일반적인 HTTP 캐시와는 차별되는Back/Foward를 위한 별도의 캐시를 제공한다. 이 때문에 위의 코드들이 사파리에서는 작동되지 않았던거다.
해결 방법은 '믿든지 말든지 (StackOverflow의 어느 개발자의 답글이었다. believe it or not.)' body 태그의 unload 이벤트에 빈 핸들러만 등록해주면 된다. 뭐 이런 경우가 있나 싶지만, 자~알 작동한다.이유는 참고 자료의 두 번째 링크를 통해 알 수 있다.
<body onunload="">
참고
라벨:
ASP.NET MVC,
Cache
'Microsoft.JET.OLEDB.4.0' 공급자는 로컬 컴퓨터에 등록할 수 없습니다.
System.Data.OleDb.OleDbDataAdapter 클래스를 생성하는데 다음과 같은 예외가 발생했다.
[2007 Office system 드라이버 : 데이터 연결 구성 요소 다운로드]
두 번째 경우는 등록된 OLE DB Provider가 x64 플랫폼을 지원하지 않기 때문이다. IIS 설정을 변경하거나 프로젝트 빌드 플랫폼 변경을 통해 x86 모듈에 대한 호환성을 추가해준다.
IIS 설정 변경 (IIS7)
IIS관리자에서 응용 프로그램 풀을 선택. 우 클릭하여 '고급 설정'을 선택한다. '32비트 응용 프로그램 사용'을 'True'로 변경한다.
빌드 플랫폼 변경 (VS2010)
프로젝트 이름을 클릭하고 우 클릭, '속성'을 선택하여 '빌드'탭의 '플랫폼 대상'을 'x86'으로 변경한다.
- 'Microsoft.Jet.OLEDB.4.0' 공급자는 로컬 컴퓨터에 등록할 수 없습니다.
- 'Microsoft.ACE.OLEDB.12.0' 공급자는 로컬 컴퓨터에 등록할 수 없습니다.
원인
구글링 결과 보통 두 가지 이유 때문에 발생하는 예외라 한다. x86 서버에서는 잘 돌아가던 웹 서비스가 x64 서버에서만 예외가 발생하니 아마도 두 번째 이유가 원인인 듯 하다.- 서버에 Office System Driver가 설치되지 않았을 경우
- x64 서버에서 웹 서비스를 호스팅할 경우
해결
첫 번째 경우는 Office System Driver를 설치하면 간단하게 해결된다.[2007 Office system 드라이버 : 데이터 연결 구성 요소 다운로드]
두 번째 경우는 등록된 OLE DB Provider가 x64 플랫폼을 지원하지 않기 때문이다. IIS 설정을 변경하거나 프로젝트 빌드 플랫폼 변경을 통해 x86 모듈에 대한 호환성을 추가해준다.
IIS 설정 변경 (IIS7)
IIS관리자에서 응용 프로그램 풀을 선택. 우 클릭하여 '고급 설정'을 선택한다. '32비트 응용 프로그램 사용'을 'True'로 변경한다.
빌드 플랫폼 변경 (VS2010)
프로젝트 이름을 클릭하고 우 클릭, '속성'을 선택하여 '빌드'탭의 '플랫폼 대상'을 'x86'으로 변경한다.
2012년 11월 12일 월요일
[MSSQL] DATEPART 함수
DATEPART(datepart, date) 함수를 통해 날짜 별 통계 쿼리 작성이 가능하다. datapart 인수를 통해 년, 월, 주, 일별로 날짜를 뽑아내서 GROUP BY를 수행한다. 자주 잊어버리는 함수라 기록 차원에서 포스팅.
-- 월 별 사용량 통계 SELECT datepart(mm, CREATE_DATE) AS '월', (sum(FILESIZE) / 1024) AS 'MB' FROM dbo.EP_FILEINFOT WHERE DIRECTORY = 'CONTENTS.GROUP.APPRMAIL_ALL' AND ISDELETED = 'N' AND CREATE_DATE > '2011-01-01' GROUP BY datepart(mm, CREATE_DATE);
참고자료
- http://msdn.microsoft.com/en-us/library/ms174420.aspx
2012년 11월 7일 수요일
[ASP.NET MVC] IControllerActivator
ASP.NET MVC 1, 2에서는 사용자 요청을 처리할 컨트롤러를 생성하는 역할을 IControllerFactory 인터페이스가 책임졌다. IContollerFactory 인터페이스는 다음과 같은 역할을 한다.
이는 클래스 당 한 가지 책임(기능)을 가진다는 단일책임원칙(SRP)에 위배된다. ASP.NET MVC 3 에서는 리팩토링을 통해 IControllerFactory의 역할을 분리하여 IControllerActivator라는 새로운 인터페이스를 추가했다.
요청을 처리할 컨트롤러가 결정되면 컨트롤러 팩토리 내부에서 IControlerActivator의 Crate 메서드가 호출된다. 사용자 정의 IControllerActivator를 사용하기 위해서는 IDependencyResolver를 통해 새로 구현된 IControllerActivator를 반환하도록 한다.
결론은,
IoC 컨테이너를 사용하려면 커스텀 컨트롤러 팩토리 클래스를 구현할게 아니라 커스텀 DependencyResolver와 ControllerActivator 클래스를 구현해야 한다는 것.
- 요청을 처리할 컨트롤러를 결정
- 컨트롤러 생성
이는 클래스 당 한 가지 책임(기능)을 가진다는 단일책임원칙(SRP)에 위배된다. ASP.NET MVC 3 에서는 리팩토링을 통해 IControllerFactory의 역할을 분리하여 IControllerActivator라는 새로운 인터페이스를 추가했다.
- IControllerFactory : 요청을 처리항 컨트롤러를 결정
- IControllerActivator : 컨트롤러를 생성
요청을 처리할 컨트롤러가 결정되면 컨트롤러 팩토리 내부에서 IControlerActivator의 Crate 메서드가 호출된다. 사용자 정의 IControllerActivator를 사용하기 위해서는 IDependencyResolver를 통해 새로 구현된 IControllerActivator를 반환하도록 한다.
결론은,
IoC 컨테이너를 사용하려면 커스텀 컨트롤러 팩토리 클래스를 구현할게 아니라 커스텀 DependencyResolver와 ControllerActivator 클래스를 구현해야 한다는 것.
참고
[ASP.NET MVC] 라우팅 데이터를 이용한 URL 생성
간단한 URL도 하드코딩하지 않고 동적으로 생성하는 버릇을 들일 필요가 있다. 귀찮다고 하드코딩 했다가는 유지보수할 때 고생한다. -_-;;
<% Url.RouteUrl(new { controller = "Home", action = "Index" }); %>
라벨:
ASP.NET MVC,
RouteUrl
피드 구독하기:
글 (Atom)