잊지 않겠습니다.

Model 객체의 경우에는 데이터의 Display class로만 주로 사용하고 있었는데. 재미있는 특징들이 이제서야 많이 보이는 것 같다.

특히 IDataError interface의 상속으로 View에서의 데이터 에러를 검증하고, 그 에러를 View에서 표시하는데 사용할 수 있는 여력이 많이 보인다.
여러가지로 재미있다고 해야지 될까나.



public class GuestResponse : IDataErrorInfo
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public bool? WillAttend { get; set; }
    public string Error { get { return null; } } // Not required for this example
    public string this[string propName]
   {
       get {
               if((propName == "Name") && string.IsNullOrEmpty(Name))
                    return "Please enter your name";
               if ((propName == "Email") && !Regex.IsMatch(Email, ".+\\@.+\\..+"))
                    return "Please enter a valid email address";
               if ((propName == "Phone") && string.IsNullOrEmpty(Phone))
                    return "Please enter your phone number";
               if ((propName == "WillAttend") && !WillAttend.HasValue)
                    return "Please specify whether you'll attend";
               return null;
             }
    }
}

참 여러가지로 사용되는 Interface가 많은 것 같다. 무언가 class를 생성할 때, 언제나 먼저 생각해줄 것이.
일단 Framework에서 지원되는 class가 있는지. 내가 사용할 action이 정의되어있는 interface는 존재하는지에 대한
생각은 항시 필요한 것 같다.

공부할 내용이 너무나 많아. --;

그리고, asp.net에서 SmtpClient를 사용할 때, 개발 환경이나 개인 환경에서 SMTP 서버를 사용할 수 없을 때, File에 지정할 수 있는 방법이 있다
web.config에 다음과 같은 설정을 넣어주면 된다.



	
		
			
				
			
		
	
Posted by Y2K
,
1. 인덱스 컬럼절의 변형

 

select ename from emp where sal * 2.1 > 950 (X)

select ename from emp where sal > 950/2.1   (O)

 

select ename from emp where to_char(hiredate, 'DDMMYY') = '250884'   (X)

select ename from emp where hiredate = to_date('250884', 'DDMMYY')    (O)

 

=> 인덱스 컬럼에 변형을 가하면 사용할수 없다. 단 변형가능 하더라도 쓰고 싶다면 쓸수야 있지만..

    create index .... on emp to_char(hiredate, 'DDMMYY') ....이렇게 해야할까.ㅋ;;

 

2. 내부적인 데이터변환

 

select * from emp where hiredate = '14-JAN-85' (X)

select * from emp hiredate = to_date('71-10-22', 'YY/DD/MM')   (O)

 

select * from emp where empno = '7936' (X)

select * from emp where empno = to_numer('7936')                   (O)

 

=> 내부적인 데이터변환에서 가장 많이 실수하는 부분은 문자값 데이터타입을 갖는 컬럼에 '값'->값 으로 하는

     유형이랄까... 딱 맞는 데이터타입을 사용해야만 함!!

 

3. NULL 조건의 사용

 

select ename from emp where comm is null          (X)

select ename from emp where comm is not null    (X)

 

select ename from emp where ename > ''            (O)

select ename from emp where comm >= 0            (O)

 

=> NULL 조건으로 검색한다는 가정하에는 거의 인덱스 풀 스캔이 일어남.적절히 사용할것!!

 

4. 부정형 조건의 사용

 

select ename from emp where deptno != 30 (X)

select ename from emp wehre deptno < 30 and deptno > 30      (O)

 

=> 논리적으로 부정형을 이용하여 인덱스를 사용하겠다는것은 말이 안됨.

5. Like 연산자 사용

 

select * from emp where ename like 'S%'         (O)

select * from emp where ename like '%S%'      (X)

 

=> %S% 부분을 꼭 쓰고 싶다면 이런식으로 하는것이...다 넣는거다.ㅋ

    AS%, BS%, ..... 본문찾기 기능은 없어지는 추세.

 

6. 최적기가 판단

 

RBO경우 무조건 탄다. CBO는 통계값을 기준으로 하기 때문에 DBA가 잘해야지..HINT를 적절히..

 

 

기타. 인덱스를 이용한 sort 회피 방법

 

select empno, ename, job, comm from emp order by empno             (정렬)

select empno, ename, job, comm from emp where empno >= 0         (정렬제거)

 

Index를 사용하지 않고 개발을 하는 경우가 많은데, 이 부분에 대한 고려는 항시 필요하다. 언제나 이런 내용까지 같이 고민을 하는 개발자가 될 수 있을지... 참 길이 멀고도 험한것 같다.
Posted by Y2K
,

AD Update source

.NET Framework 2009. 11. 16. 09:44
AD와 같은 분산 시스템에서의 업데이트는 개발자뿐 아니라 시스템 관리자들에게 매우 중요한 일이 된다.
특히 Exchange나 Domain에서의 권한문제 등을 다룰때, AD의 값을 어떻게 변경하느냐에 따라서 각 시스템의 운영자체가 달라지기 때문에 특히 주의를 해야지 된다. 그리고, 시스템측에서는 이러한 AD의 일괄 업데이트를 Powershell이 나오기 전에는 할 방법이 마땅치 않아서 곤란해지는 경우가 많다. PowerShell의 경우에는 매우 쉽게 이런 일을 할 수 있다.

먼저, AD는 모두 DirectoryEntry로 접근을 한다. 각 DirectoryEntry를 통해서 AD Query를 이용한 결과값을 차례대로 업데이트를 하는 것이 가장 유용한 방법이다. 

string ldap = String.Format("LDAP://{0}", LdapPath);  //AD Path 설정

using(DirectoryEntry entry = new DirectoryEntry(ldap, UserName, Password, AuthenticationTypes.Sealing))
{
    //AD Search query
    using(DirectorySearcher searcher = new DirectorySearcher(entry, filter, null, SearchScope.Subtree))
    {
        //Update 할 item의 limit 갯수 설정, 너무나 많은 값들을 업데이트 하는 경우에, 실수라도 하게 되면 큰일도 날수도 있고.;
        searcher.SizeLimit = Buffer;
        SearchResultCollection results = searcher.FindAll();

        foreach(SearchResult result in results)
        {
            try
            {
                //각 Entry의 Directory 값들을 모두 가지고 온다. AD에서의 하나의 Item은 여러개의 Property로 구성이 되기 때문에, 각 Property의 값들의 변경을 행할때 유용하다.
                DirectoryEntry objectEntry = result.GetDirectoryEntry();
                //integer값으로 변경시켜주는 상태이다. 각 값의 type에 따라서 변경하게 해주는 것은 좀더 연구가 필요하다.
                int changeValue = int.Parse(value);
                objectEntry.Properties[propertyName].Value = changeValue;
                objectEntry.CommitChanges();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
}
Posted by Y2K
,

IIS Configuration

.NET Framework 2009. 10. 9. 15:22
IIS를 직접 제어해서 WebSite를 구성해주는 Setup 파일이라던지, 아니면 자신의 요구대로 IIS의 설정을 변경할 수 있는 방법을 제공

참고 : 
http://www.iis.net/ConfigReference

Microsoft.Web.Administration를 사용하면 IIS 7.0에서부터 사용되는 모든 설정의 Config를 변경시킬 수 있다. 기본적으로 복사되는 Machine.config의 세부 설정을 변경시켜줄 수 있게 된다. 간단히 Wrapping시킨 IisSite class의 코드는 다음과 같다. 




public class IisSite
  {
      public string SiteName { get; private set; }
      public string LastErrorMessage { get; private set; }

      public IisSite(string siteName)
      {
          SiteName = siteName;
      }

      public bool AddApplication(string applicationPool, string applicationName, string path)
      {
          try
          {
              using (ServerManager mgr = new ServerManager())
              {
                  Site site = mgr.Sites[SiteName];
                  if (site != null)
                  {
                      string appName;
                      if(applicationName.StartsWith("/"))
                      {
                          appName = applicationName;
                      }
                      else
                      {
                          appName = "/" + applicationName;
                      }

                      site.Applications.Add(appName, path);
                      Application app = site.Applications[appName];
                      app.ApplicationPoolName = applicationPool;
                      mgr.CommitChanges();
                  }

                  return true;
              }
          }
          catch(Exception ex)
          {
              LastErrorMessage = ex.StackTrace;
              return false;
          }
      }

      public bool SetAuthicationForAnonymous(string applicationName, bool enable)
      {
          return SetAuthicationEnable(applicationName, IisConfigConstant.AnonymousAuth, enable);
      }

      public bool SetAuthicationForBasic(string applicationName, bool enable)
      {
          return SetAuthicationEnable(applicationName, IisConfigConstant.BasicAuth, enable);
      }

      private bool SetAuthicationEnable(string applicationName, string authType, bool enable)
      {
          try
          {
              string appPath = string.Format("{0}/{1}", SiteName, applicationName);
              using (ServerManager mgr = new ServerManager())
              {
                  Configuration config = mgr.GetApplicationHostConfiguration();
                  ConfigurationSection basicAuthenticationSection = config.GetSection(authType, appPath);
                  basicAuthenticationSection[IisConfigConstant.Enabled] = enable;
                  mgr.CommitChanges();

                  return true;
              }
          }
          catch(Exception ex)
          {
              LastErrorMessage = ex.Message;
              return false;
          }
      }

      public bool SetDefaultDomainForBasic(string applicationName, string defaultDomain)
      {
          return SetAuthDefaultDomain(applicationName, IisConfigConstant.BasicAuth, defaultDomain);
      }

      private bool SetAuthDefaultDomain(string applicationName, string authType, string defaultDomainName)
      {
          try
          {
              using (ServerManager mgr = new ServerManager())
              {
                  string appPath = string.Format("{0}/{1}", SiteName, applicationName);

                  //NOTE : Set Auth
                  Configuration config = mgr.GetApplicationHostConfiguration();
                  ConfigurationSection basicAuthenticationSection = config.GetSection(authType, appPath);
                  basicAuthenticationSection[IisConfigConstant.DefaultDomain] = defaultDomainName;
                  mgr.CommitChanges();

                  return true;
              }
          }
          catch(Exception ex)
          {
              LastErrorMessage = ex.Message;
              return false;
          }
      }
Posted by Y2K
,

WinRm 설정

OS 자료들 2009. 9. 16. 02:02
windows의 remote command를 사용할 수 있는 너무나 멋진 서비스.

linux에서 ssh를 이용한 command set을 날리는 것을 볼때마다 느끼는 부러움은 이제 없어지는 것인가.. 라는 생각이 든다.
기본적으로 windows 2003 이상부터 WS-Management가 설치되어 있는 경우에 사용 가능하다.

기본적인 컨셉은 기존의 wmi query의 remote와 유사하다는 느낌이 든다. 그렇지만, RPC를 사용하는 것이 아닌, http://를 사용하는 것으로 protocol면이나 사용하는 것에 있어서 매우 편하게 사용가능한 것을 알 수 있다.

먼저, 기본적으로 winrm의 설정이 필요하다.


기본적으로 사용자가 설정할 내용들이 거의 없다. 처음에 windows firewall의 예외 port 설정을 quickconfig가 대신해준다는 점을 제외하고는 winrm s winrm/config @{key:value} 형태로 조작하는 것이나 거의 비슷하다.

일단 기본적인 명령어들은
winrm get, winrm set, winrm invoke로 사용가능한다. invoke의 경우에는 wmi query를 remote로 vb script나 Powershell에서 사용하는 것과 동일하고 너무나 재미있어 보이는 것이 winrm으로 Service를 올린 이후의 작업들이다.

먼저 기본적인 quickconfig를 마친 설정은 다음과 같다.


설정 내용을 보면 webservice 구축이 되어있다는 느낌을 강하게 받는다. IP FIlter부터 Timeout, Max-Connection 숫자, UnencryptAllowed 등 잘 거의 web service를 사용하는 것과 동일하게 사용할 수 있다. 다만 주의 할점이있다면 Service 설정 뿐 아니라, Client에서도 기본 설정을 잡아주어야지만 client를 이용해서 server에 접근 할 수 있다는 점이다.

winrm의 하이라이트. http://를 이용해서 cmd set을 이용해보자~

winrs를 이용해서 ipconfig 명령어를 날린 상태이다. 이를 이용하면 따로 webservice를 올리지 않고, console application으로 작성해서 그 결과를 return시켜줄 수 있는 멋진 환경이 만들어진다. 관리자들 뿐아니라 기본적으로 개발자들도 이 부분에 대한 공부가 좀 더 필요할 것 같다. 생각만하면 무궁무진하게 사용할 수 있는 분야가 많으니까 말이다.

지금 windows 2003에서 사용되고 있는 WS-Management 1.1에서는 단순 remote http/https만을 지원한다. 그렇지만, WS-Management 2.0에서는 더 멋진 것을 지원한다. PowerShell에서 remote computer와의 PS-Session을 이용한 Remote Powershell command를 할 수 있다!

Remote Powershell command를 지원하게 되는 경우에 기존의 Exchange 2007, SCVMM, SCMON 등의 resource를 remote로 호출해서 그 결과를 사용할 수 있다는 뜻이된다. 이 부분은 PowerShell의 Invoke-Command 부분을 좀 더 공부해볼 필요가 있을 것 같다.





Posted by Y2K
,
set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin

set diffexpr=MyDiff()
function MyDiff()
  let opt = '-a --binary '
  if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif
  if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif
  let arg1 = v:fname_in
  if arg1 =~ ' ' | let arg1 = '"' . arg1 . '"' | endif
  let arg2 = v:fname_new
  if arg2 =~ ' ' | let arg2 = '"' . arg2 . '"' | endif
  let arg3 = v:fname_out
  if arg3 =~ ' ' | let arg3 = '"' . arg3 . '"' | endif
  let eq = ''
  if $VIMRUNTIME =~ ' '
    if &sh =~ '\<cmd'
      let cmd = '""' . $VIMRUNTIME . '\diff"'
      let eq = '"'
    else
      let cmd = substitute($VIMRUNTIME, ' ', '" ', '') . '\diff"'
    endif
  else
    let cmd = $VIMRUNTIME . '\diff'
  endif
  silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3 . eq
endfunction

set gfn=나눔고딕코딩:h10:cANSI
set bdlay=100
set backspace=indent,eol,start
set number
set ai
set ts=4
set sw=4
"set vb  " visual bell
set background=dark

"
" geometry setting
set lines=57
set columns=120
winpos 0 0

"
" Color scheme
highlight Normal     guifg=Grey80 guibg=Black
highlight Search     guifg=Black guibg=lightred
highlight Visual     guifg=Grey25
highlight Cursor     guifg=Black guibg=lightblue
highlight Special    guifg=Orange
highlight Comment    guifg=#80a0ff
highlight StatusLine guifg=darkcyan  guibg=white
highlight Statement  guifg=Orange gui=NONE
highlight Type      gui=NONE
Posted by Y2K
,
web.config 및 app.config에서 수많은 xml을 보다보면 무엇을 보고 사용해야지 될지 모르게 될 때가 많다. -_-

지금까지는 조금 어색하게 사용하고 있었던 application config section에 대한 내용을 한번 정리해보자. 

Section group에 대한 예시는 다음과 같다. 
  
    
        
        
  
section group의 name을 정할 수 있고, 그렇게 되면 configuration에 section group의 이름이 들어갈 수 있다.
configSections에 section group이 지정되어있지 않으면, section not found라는 web.config error가 나타나게 된다. 

여기에서 section name과 permission의 경우에는 일반적인 type에 따라서 정해주면 되는데, 그것보다 더 중요한 것이 뒤에 나오는 type값이다.
class full name, assembly name 으로 구성이 되어 있는 것을 볼 수 있다. 이는 사용자 section을 만들었을 때에 중요한 항목이 되는데, 자신이 만들어준 ConfigurationSection을 상속받은 ConfigurationSection class를 이용해서 handling할 class를 지정해주어야지 된다. 

예를 들어 주로 사용하는 web service url group을 만들었을 때에는 다음과 같다. 

  
    
      http://localhost/MPSWS/HostedActiveDirectory/Service.asmx
      http://localhost/MPSWS/Hostedsharepoint2007/Service.asmx
      http://localhost/mpsws/hostedemail2007/service.asmx
      http://localhost/mpsws/hostedsignup/service.asmx
      http://localhost/mpsws/managedplans/service.asmx
      http://localhost/mpsws/Exchange2007ResourceManager/service.asmx
      http://localhost/mpsws/HostedMobility2007/service.asmx
      http://localhost/mpsws/ManagedEmail2007/service.asmx
      http://localhost/mpsws/managedplans/service.asmx
    
    
      http://localhost/MPSWS/HostedActiveDirectory/Service.asmx
      http://localhost/MPSWS/Hostedsharepoint2007/Service.asmx
      http://localhost/mpsws/hostedemail2007/service.asmx
      http://localhost/mpsws/hostedsignup/service.asmx
      http://localhost/mpsws/managedplans/service.asmx
      http://localhost/mpsws/Exchange2007ResourceManager/service.asmx
      http://localhost/mpsws/HostedMobility2007/service.asmx
      http://localhost/mpsws/ManagedEmail2007/service.asmx
      http://localhost/mpsws/managedplans/service.asmx
    
  
public sealed class WebServiceUrlCollection : ConfigurationSection
{
    private readonly XmlDocument xmlDoc = new XmlDocument();
    public Dictionary MapTable { get; private set; }

    public string GetValue(string key)
    {
        if (MapTable == null)
        {
            Create();
        }
        if(MapTable.ContainsKey((key)))
        {
            return MapTable[key.ToString()];    
        }
        else
        {
            return string.Empty;
        }
    }

    private void Create()
    {
        MapTable = new Dictionary();
        foreach (XmlNode node in xmlDoc.ChildNodes[0].ChildNodes)
        {
            MapTable.Add(node.Name, node.InnerText); 
        }
    }
    protected override void DeserializeSection(XmlReader reader)
    {
        xmlDoc.Load(reader);
        Create();
    }
}
Posted by Y2K
,
Color Setting을 한번 뒤져보다가 괜찮은 아이를 찾아서 upload.

이상하게 계속해서 font, color에 끌리는 이유가 뭘까.;

Posted by Y2K
,

MS SQL Paging query

.NET Framework 2009. 8. 19. 11:52
MS SQL 2005부터 사용가능한 ROW_NUMBER()를 이용한 Paging query


DECLARE @startRow INT
DECLARE @endRow INT
SELECT * FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY LogonName) AS rownum FROM Product) ProductOrdered WHERE rownum > @startRow AND @endRow > rownum
간단히 사용해보면 시작 위치와 마지막 위치만을 지정해주고, Order되는 Column을 설정해주면 된다. 
일단 MS SQL 2005에서부터 사용할 수 있는 함수라서 단점을 가지고 있긴 하지만, 그래도 깔끔하고 무엇보다 속도가 매우 빠르다.
예전에 사용하던 SELECT TOP * FROM ~ 쿼리의 경우에는 뒤로 가면 갈 수록 query가 느려지는 단점을 가지고 있는데, 이를 전혀 신경 쓰지 않아도 되는 좋은 함수이다. 
Posted by Y2K
,
1의 경우에서 Strategy Pattern을 사용해서 각각 Marin, Firebet, Medic을 구현을 다 해놓고 나니, Zerg Unit를 다른 개발자가 개발해서 들고 왔다.
그런데, 각 unit의 method가 다르기 때문에 사용할 수가 객체가 어떤 형태인지에 따라 접근 방법을 달리 해줘야지 되는 문제가 발생되었다. 이럴 때에, Method의 Interface를 한번 덮어줘서 사용하고자 하는 interface로 변경해주는 것만으로, 이런 문제를 해결 할 수 가 있다. 이것이 Adapter Pattern이다. 

기본적으로 Zerg Unit는 MoveTo를 갖지만, Attack이 아닌 Bite Method를 갖는다. 
그렇지만, 본질적으로 Bite, RunTo Method는 BaseUnit의 Attack, MoveTo와 유사 동작을 하기 때문에
Public으로 선언된 각 Method를 변경시켜주면 된다. 

public abstract class ZergUnitBase
{
    //Terran 의 Unit과는 다른 Bite와 Run Method를 가지고 있다. 
    public abstract String Bite();
    public abstract String Run(String direction);
}

따라서, BaseUnit과의 호환성을 맞추어주기 위해서 ZergUnitToBaseUnit이라는 Adapter를 구성해준다.

public class ZergUnitToBaseUnit : BaseUnit
{
    private readonly ZergUnitBase zergUnitBase;

    public ZergUnitToBaseUnit(ZergUnitBase zergUnitBase)
    {
        this.zergUnitBase = zergUnitBase;
    }

    public override string Attack()
    {
        return zergUnitBase.Bite();
    }

    public override string MoveTo(string direction)
    {
        return zergUnitBase.Run(direction);
    }
}

구성된 zerg unit을 이용해서 terran과 zerg의 난타전을 테스트하면 다음과 같다.

BaseUnit unit1 = new ZergUnitToBaseUnit(new Zergling());
BaseUnit unit2 = new ZergUnitToBaseUnit(new Hydralisk());

Console.WriteLine(unit1.Attack());
Console.WriteLine(unit2.MoveTo("Terran"));
보면, Zerg와 Terran의 Unit을 다루는 법이 동일하게 변경되었다. 다른 인터페이스와 동일하나, class의 변경은 이루어지지 않는다.

Posted by Y2K
,