Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 2개 있습니다.)
.NET Framework: 786. ASP.NET - HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상
; https://www.sysnet.pe.kr/2/0/11587

디버깅 기술: 221. WinDbg 분석 사례 - ASP.NET HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/13916




WinDbg 분석 사례 - ASP.NET HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상 - 두 번째 이야기

아래와 같이 덤프 파일을 분석해,

windbg 분석 사례 - x86 ASP.NET 웹 응용 프로그램의 CPU 100% 현상 (4)
; https://www.sysnet.pe.kr/2/0/13914

requestValidationMode 값을 4.0으로 설정하면 문제가 발생하지 않을 거라고 했는데, 그래도 여전히 해당 현상이 재현된다는 소식과 함께 다시 덤프 파일을 받았습니다.

이럴 땐 자연스럽게, ^^; 제 눈으로 본 것이 아니기 때문에 정말 4.0으로 설정했는지 확인해야 합니다. 어떻게 할 수 있을까요? ^^

우선 HttpRuntimeSection.RequestValidationMode 속성의 역어셈블 코드를 보면,

[ConfigurationProperty("requestValidationMode", DefaultValue = "4.0")]
[TypeConverter(typeof(VersionConverter))]
public Version RequestValidationMode
{
    get
    {
        if (this._requestValidationMode == null)
        {
            this._requestValidationMode = (Version)base[HttpRuntimeSection._propRequestValidationMode];
        }
        return this._requestValidationMode;
    }
    set
    {
        this._requestValidationMode = value;
        base[HttpRuntimeSection._propRequestValidationMode] = value;
    }
}

보는 바와 같이 _requestValidationMode 필드에 값이 보관됩니다. 다행히 HttpRuntimeSection은 Web Application에 1개의 인스턴스, 또는 다른 이유로 인해 1~2개 정도 더 생성될 것이라고 짐작할 수 있으므로 GC Heap에 존재할 그 인스턴스를 검색해 보면 됩니다.

// 우선 해당 타입의 MethodTable을 알아내고,
0:000> !name2ee System.Web.dll!System.Web.Configuration.HttpRuntimeSection
Module:      19c1a4c4
Assembly:    System.Web.dll
Token:       020006fe
MethodTable: 1a7c4248
EEClass:     1b5966e0
Name:        System.Web.Configuration.HttpRuntimeSection

// GC Heap에서 HttpRuntimeSection 인스턴스를 검색
0:000> !dumpheap -mt 1a7c4248
 Address       MT     Size
0b6522c8 1a7c4248      112     
0b652438 1a7c4248      112     

Statistics:
      MT    Count    TotalSize Class Name
1a7c4248        2          224 System.Web.Configuration.HttpRuntimeSection
Total 2 objects
Fragmented blocks larger than 0.5 MB:
    Addr     Size      Followed by
0a862394    0.6MB         0a8f6234 System.Byte[]

보는 바와 같이 2개의 인스턴스가 있는데요, 각각을 덤프해 보면,

// 인스턴스 1개는 _requestValidationMode 필드가 비어 있고,

0:000> !do 0b6522c8
Name:        System.Web.Configuration.HttpRuntimeSection
MethodTable: 1a7c4248
EEClass:     1b5966e0
Size:        112(0x70) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
0663aa48  4000198       30       System.Boolean  1 instance        0 _bDataToWrite
...[생략]...
0663c9b0  4002e15       50         System.Int32  1 instance       -1 _RequestLengthDiskThresholdBytes
1a62e23c  4002e17       3c       System.Version  0 instance 00000000 _requestValidationMode
0663c9b0  4002e18       54         System.Int32  1 instance        0 _MaxUrlLength
...[생략]...

// 다른 인스턴스에는 4.0.-1.-1 값이 설정됨

0:000> !do 0b652438
Name:        System.Web.Configuration.HttpRuntimeSection
MethodTable: 1a7c4248
EEClass:     1b5966e0
Size:        112(0x70) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
0663aa48  4000198       30       System.Boolean  1 instance        0 _bDataToWrite
...[생략]...
0663c9b0  4002e15       50         System.Int32  1 instance    81920 _RequestLengthDiskThresholdBytes
1a62e23c  4002e17       3c       System.Version  0 instance 0b652664 _requestValidationMode
0663c9b0  4002e18       54         System.Int32  1 instance      260 _MaxUrlLength
...[생략]...

0:000> !do 0b652664
Name:        System.Version
MethodTable: 1a62e23c
EEClass:     1a63b0c4
Size:        24(0x18) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
0663c9b0  400073a        4         System.Int32  1 instance        4 _Major
0663c9b0  400073b        8         System.Int32  1 instance        0 _Minor
0663c9b0  400073c        c         System.Int32  1 instance       -1 _Build
0663c9b0  400073d       10         System.Int32  1 instance       -1 _Revision
19c14e2c  400073e      1d0        System.Char[]  0   shared   static SeparatorsArray

그러니까, requestValidationMode 값을 4.0으로 설정한 것이 맞고, 그럼에도 불구하고 문제가 발생하고 있는 것입니다.




그렇다면, 분명히 어떤 식으로든 EnableGranularValidation 코드가 수행되고 있다는 건데요, 이건 어떻게 확인할 수 있을까요? ^^

이를 위해 WinDbg를 동원할 필요는 없고, 위의 분석 대상이었던 응용 프로그램의 유형이 ASP.NET MVC 프로젝트였으므로 이에 대한 간단한 예제 프로젝트를 Visual Studio에서 생성한 후 쿠키를 사용하는 코드를 넣어,

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var oldCookie = this.Request.Cookies["test"];
        this.Response.Cookies.Add(new HttpCookie("test", "testValue") { Expires = DateTime.Now.AddDays(1) });

        return View();
    }

    // ...[생략]...
}

디버깅을 시작해 솔루션 탐색기의 "External Sources"로부터 HttpCookieCollection 소스 코드를 열어 BP를 걸어보면 됩니다.

cookie_validation_on_mvc_1.png

실제로, web.config의 requestValidationMode를 4.0으로 설정해도,

<httpRuntime targetFramework="4.8" requestValidationMode="4.0" />

동일하게 BP가 걸리는데요, 이때의 callstack을 따라가 보면,

>    System.Web.dll!System.Web.HttpCookieCollection.EnableGranularValidation(System.Web.ValidateStringCallback validationCallback = {Method = Inspecting the state of an object in the debuggee of type System.Delegate is not supported in this context.}) Line 127 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpRequest.Cookies.get() Line 1225   C#  Symbols loaded.
    net48_mvc.dll!net48_mvc.Controllers.HomeController.Index() Line 14  C#  Symbols loaded.
    [Lightweight Function]      Annotated Frame
    System.Web.Mvc.dll!System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext controllerContext = {System.Web.Mvc.ControllerContext}, System.Web.Mvc.ActionDescriptor actionDescriptor = {System.Web.Mvc.ReflectedActionDescriptor}, System.Collections.Generic.IDictionary<string, object> parameters) Line 253  C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeSynchronousActionMethod.AnonymousMethod__9_0(System.IAsyncResult asyncResult, System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation innerInvokeState) Line 304 C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.__Canon, System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation>.CallEndDelegate(System.IAsyncResult asyncResult) Line 224   C#  Symbols loaded.
    // ...[생략]...
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 386  C#  Symbols loaded.
    [AppDomain Transition]      Annotated Frame

관련 코드의 역어셈블 결과에서,

// HttpRequest.cs

public HttpCookieCollection Cookies
{
    get
    {
        EnsureCookies();
        if (_flags[4])
        {
            _flags.Clear(4);
            ValidateCookieCollection(_cookies);
        }
        return _cookies;
    }
}

private void ValidateCookieCollection(HttpCookieCollection cc)
{
	if (GranularValidationEnabled)
	{
		cc.EnableGranularValidation(delegate(string key, string value)
        {
            ValidateString(value, key, RequestValidationSource.Cookies);
        });
		return;
	}
	int count = cc.Count;
	for (int i = 0; i < count; i++)
	{
		string key2 = cc.GetKey(i);
		string value2 = cc.Get(i).Value;
		if (!string.IsNullOrEmpty(value2))
		{
			ValidateString(value2, key2, RequestValidationSource.Cookies);
		}
	}
}

Cookies get 메서드로부터 결국 _flags[4] 값으로 인해 EnableGranularValidation이 호출되고 있음을 알 수 있습니다. 그리고 다시, 그것은 GranularValidationEnabled get 속성이 true를 반환하기 때문인데,

// HttpRequest.cs

private const int granularValidationEnabled = 1073741824; // 0x40000000

private bool GranularValidationEnabled => _flags[0x40000000]; // 0x40000000

internal void EnableGranularRequestValidation()
{
	_flags[0x40000000] = true;
}

따라서 EnableGranularRequestValidation 메서드가 호출된 적이 있다는 것이므로 이것도 BP를 걸어 확인하면, 호출 스택이 이렇게 나오고,

>    System.Web.dll!System.Web.HttpRequest.EnableGranularRequestValidation() Line 2672   C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.ProcessRequestInit(System.Web.HttpContextBase httpContext = {System.Web.HttpContextWrapper}, out System.Web.Mvc.IController controller = null, out System.Web.Mvc.IControllerFactory factory = null) Line 168  C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.BeginProcessRequest(System.Web.HttpContextBase httpContext, System.AsyncCallback callback = {Method = {System.Reflection.RuntimeMethodInfo}}, object state = null) Line 86 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() Line 648 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.ExecuteStepImpl(System.Web.HttpApplication.IExecutionStep step) Line 3596 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step = {System.Web.HttpApplication.CallHandlerExecutionStep}, ref bool completedSynchronously = false) Line 3622    C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error) Line 1161 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb) Line 4054    C#  Symbols loaded.
    System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr = {System.Web.Hosting.IIS7WorkerRequest}, System.Web.HttpContext context = {System.Web.HttpContext}) Line 1407  C#  Symbols loaded.
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext = 0x0000026e78687998, System.IntPtr moduleData, int flags) Line 461   C#  Symbols loaded.
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 386  C#  Symbols loaded.
    [Native to Managed Transition]      Annotated Frame
    [Managed to Native Transition]      Annotated Frame
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 499    C#  Symbols loaded.
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 386  C#  Symbols loaded.
    [AppDomain Transition]      Annotated Frame

Mvc 프레임워크에 놓인 ProcessRequestInit 메서드에서 ValidationUtility.EnableDynamicValidation 메서드를 호출하며, 그 원인은 다시 ValidationUtility.IsValidationEnabled가 true를 반환하기 때문입니다.


// MvcHandler.cs (System.Web.Mvc.dll)
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
    HttpContext current = HttpContext.Current;
    if (current != null && ValidationUtility.IsValidationEnabled(current) == true)
    {
        ValidationUtility.EnableDynamicValidation(current);
    }
    AddVersionHeader(httpContext);
    RemoveOptionalRoutingParameters();
    string requiredString = RequestContext.RouteData.GetRequiredString("controller");
    factory = ControllerBuilder.GetControllerFactory();
    controller = factory.CreateController(RequestContext, requiredString);
    if (controller == null)
    {
        throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[2]
        {
            factory.GetType(),
            requiredString
        }));
    }
}

// Microsoft.Web.Infrastructure.dll

[EditorBrowsable(EditorBrowsableState.Never)]
public static class ValidationUtility
{
    // ...[생략]...

    [SecuritySafeCritical]
    public static bool? IsValidationEnabled(HttpContext context)
    {
        if (DynamicValidationShimReflectionUtil.Instance != null)
        {
            return DynamicValidationShimReflectionUtil.Instance.IsValidationEnabled(context);
        }
        return CollectionReplacer.IsValidationEnabled(context);
    }
}

// System.Web.dll

internal static class DynamicValidationShim
{
    internal static bool IsValidationEnabled(HttpContext context)
    {
        return context.Request.ValidateInputWasCalled;
    }

    // ...[생략]...
}

// HttpRequest.cs (System.Web.dll)

internal bool ValidateInputWasCalled => _flags[32768]; // 0x8000

public void ValidateInput()
{
    if (!ValidateInputWasCalled && !RequestValidationSuppressed)
    {
        _flags.Set(32768);
        _flags.Set(1);
        _flags.Set(2);
        _flags.Set(4);
        _flags.Set(64);
        _flags.Set(128);
        _flags.Set(256);
        _flags.Set(512);
        _flags.Set(8);
    }
}

끝이 보이는군요. ^^ 이제 ValidateInput이 호출된 위치를 다시 BP를 걸어 확인해 보면,

internal void ValidateInputIfRequiredByConfig()
{
    RuntimeConfig config = RuntimeConfig.GetConfig(Context);
    HttpRuntimeSection httpRuntime = config.HttpRuntime;
    if (CanValidateRequest())
    {
        string path = Path;
        if (path.Length > httpRuntime.MaxUrlLength)
        {
            throw new HttpException(400, SR.GetString("Url_too_long"));
        }
        if (QueryStringText.Length > httpRuntime.MaxQueryStringLength)
        {
            throw new HttpException(400, SR.GetString("QueryString_too_long"));
        }
        char[] requestPathInvalidCharactersArray = httpRuntime.RequestPathInvalidCharactersArray;
        if (requestPathInvalidCharactersArray != null && requestPathInvalidCharactersArray.Length != 0)
        {
            int num = path.IndexOfAny(requestPathInvalidCharactersArray);
            if (num >= 0)
            {
                string text = new string(path[num], 1);
                throw new HttpException(400, SR.GetString("Dangerous_input_detected", "Request.Path", text));
            }
            _flags.Set(65536);
        }
    }
    Version requestValidationMode = httpRuntime.RequestValidationMode;
    if (requestValidationMode == VersionUtil.Framework00)
    {
        _flags[int.MinValue] = true;
    }
    else if (requestValidationMode >= VersionUtil.Framework40)
    {
        ValidateInput();
        if (requestValidationMode >= VersionUtil.Framework45)
        {
            EnableGranularRequestValidation();
        }
    }
}

이렇게 requestValidationMode >= VersionUtil.Framework40인 상황에서 호출된 것이 MVC Framework에서는 (마이크로소프트가 의도한 것인지, 논리적으로 버그인 것인지 알 수 없으나) 기본적으로 Cookie의 EnableGranularValidation 기능을 활성화시켜버리는 것입니다.

결국, MVC 프로젝트라면 web.config에 requestValidationMode 값을 오히려 4.0 미만으로 설정해야 하는데, 가능한 값이 정해져 있으므로 2.0 정도로 내려야 합니다.




부가적으로 하나 더 정리하자면, ValidationUtility의 경우 중간에 DynamicValidationShimReflectionUtil.Instance를 접근하는데,

// ValidationUtility.cs (Microsoft.Web.Infrastructure.dll)

[SecuritySafeCritical]
public static bool? IsValidationEnabled(HttpContext context)
{
    if (DynamicValidationShimReflectionUtil.Instance != null)
    {
        return DynamicValidationShimReflectionUtil.Instance.IsValidationEnabled(context);
    }
    return CollectionReplacer.IsValidationEnabled(context);
}

이것은 Reflection을 이용해 System.Web.dll에 있는 Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim 타입 정보를 로드하는 역할을 합니다.

// DynamicValidationShimReflectionUtil.cs (Microsoft.Web.Infrastructure.dll)

namespace Microsoft.Web.Infrastructure.DynamicValidationHelper;

[SecurityCritical]
internal sealed class DynamicValidationShimReflectionUtil
{
    // ...[생략]...

    [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We catch and ignore all errors because we do not want to bring down the application.")]
    private static DynamicValidationShimReflectionUtil GetInstance()
    {
        try
        {
            DynamicValidationShimReflectionUtil dynamicValidationShimReflectionUtil = new DynamicValidationShimReflectionUtil();
            Type type = CommonAssemblies.SystemWeb.GetType("Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim", throwOnError: false);
            if (type == null)
            {
                return null;
            }
            MethodInfo method = CommonReflectionUtil.FindMethod(type, "EnableDynamicValidation", isStatic: true, new Type[1] { typeof(HttpContext) }, typeof(void));
            dynamicValidationShimReflectionUtil.EnableDynamicValidation = CommonReflectionUtil.MakeDelegate<Action<HttpContext>>(method);
            CommonReflectionUtil.Assert(dynamicValidationShimReflectionUtil.EnableDynamicValidation != null);
            MethodInfo method2 = CommonReflectionUtil.FindMethod(type, "IsValidationEnabled", isStatic: true, new Type[1] { typeof(HttpContext) }, typeof(bool));
            dynamicValidationShimReflectionUtil.IsValidationEnabled = CommonReflectionUtil.MakeDelegate<Func<HttpContext, bool>>(method2);
            CommonReflectionUtil.Assert(dynamicValidationShimReflectionUtil.IsValidationEnabled != null);
            MethodInfo method3 = CommonReflectionUtil.FindMethod(type, "GetUnvalidatedCollections", isStatic: true, new Type[3]
            {
                typeof(HttpContext),
                typeof(Func<NameValueCollection>).MakeByRefType(),
                typeof(Func<NameValueCollection>).MakeByRefType()
            }, typeof(void));
            dynamicValidationShimReflectionUtil.GetUnvalidatedCollections = CommonReflectionUtil.MakeDelegate<GetUnvalidatedCollectionsCallback>(method3);
            CommonReflectionUtil.Assert(dynamicValidationShimReflectionUtil.GetUnvalidatedCollections != null);
            return dynamicValidationShimReflectionUtil;
        }
        catch
        {
            return null;
        }
    }
}

그리고 System.Web.dll에 있는 DynamicValidationShim은 마치 "Microsoft.Web.Infrastructure.dll"에서 접근할 수 있는 통로를 열어두는 것처럼 구현돼 있습니다.

// DynamicValidationShim.cs (System.Web.dll)
using System;
using System.Collections.Specialized;
using System.Web;

namespace Microsoft.Web.Infrastructure.DynamicValidationHelper;

internal static class DynamicValidationShim
{
    internal static void EnableDynamicValidation(HttpContext context)
    {
        context.Request.EnableGranularRequestValidation();
    }

    internal static bool IsValidationEnabled(HttpContext context)
    {
        return context.Request.ValidateInputWasCalled;
    }

    internal static void GetUnvalidatedCollections(HttpContext context, out Func<NameValueCollection> formGetter, out Func<NameValueCollection> queryStringGetter)
    {
        UnvalidatedRequestValues unvalidated = context.Request.Unvalidated;
        formGetter = () => unvalidated.Form;
        queryStringGetter = () => unvalidated.QueryString;
    }
}

사실 Microsoft.Web.Infrastructure.dll은 System.Web.dll을 직접 참조하고 있으므로 저런 식으로 접근할 필요가 없습니다. 그런데도, 이렇게 구현된 것은...? 아마도 닷넷 프레임워크의 BCL에 기본 포함된 System.Web.dll과는 달리 Microsoft.Web.Infrastructure.dll의 경우 .NET Framework 버전에 의존적이지 않게 만들 목적이었지 않았을까 싶습니다. 일례로, .NET 3.5 버전의 System.Web.dll에는 DynamicValidationShim 타입이 없다는 식의 고려를 한 것이 아닐까...라고 추측해 봅니다. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 4/23/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 166  167  168  169  170  171  172  173  174  175  176  177  [178]  179  180  ...
NoWriterDateCnt.TitleFile(s)
536정성태9/12/200732367.NET Framework: 97. WCF : netTcpBinding에서의 각종 Timeout 값 설명 [11]
535정성태9/11/200729846.NET Framework: 96. WCF - PerSession에서의 클라이언트 연결 관리 [5]
534정성태9/3/200725323개발 환경 구성: 29. VHD 파일 크기 줄이기
533정성태9/2/200728036개발 환경 구성: 28. CA 서비스 - 사용자 정의 템플릿 유형 추가
532정성태9/2/200730564개발 환경 구성: 27. AD CA에서 Code Signing 인증서 유형 추가 방법
531정성태9/2/200726326.NET Framework: 95. WCF에서의 DataTable 사용
530정성태9/1/200722886.NET Framework: 94. WCF 예외에 대한 시행착오
529정성태8/31/200725731.NET Framework: 93. WCF - DataContract와 KnownType 특성 [1]
528정성태8/30/200720385오류 유형: 47. VPC - 네트워크 어댑터 MAC 주소 중복 오류
527정성태8/30/200730454Team Foundation Server: 20. 잠긴 파일을 강제로 해제 [2]
526정성태8/29/200720361오류 유형: 46. VS.NET 2008 - ASP.NET 디버깅 : Strong name validation failed.
525정성태8/27/200722599VS.NET IDE: 54. VS.NET 2008 - 새롭게 도입되는 XSD Schema Designer
524정성태8/23/200740097오류 유형: 45. 요청한 작업은, 사용자가 매핑한 구역이 열려 있는...
523정성태8/16/200722809VS.NET IDE: 53. VS.NET 2008 - 서비스 참조 시 기존 데이터 컨테이너 DLL 사용
522정성태8/13/200726403VS.NET IDE: 52. VS.NET 2008 - WCF를 위한 디버깅 환경 개선
521정성태8/8/200726390.NET Framework: 92. XmlSerializer 생성자의 실행 속도를 올리는 방법 - 두 번째 이야기 [3]
520정성태8/7/200721599VS.NET IDE: 51. Visual Studio 2008 베타 2 설치
519정성태7/27/200727979오류 유형: 44. System.BadImageFormatException [2]
518정성태7/26/200728999오류 유형: 43. System.ComponentModel.LicenseException [1]
517정성태7/19/200717347개발 환경 구성: 26. VPC - 일반 사용자 계정으로 구동
516정성태7/19/200720504오류 유형: 42. TFS - Error loading menu: Index was outside the bounds of the array [2]
515정성태7/18/200728168오류 유형: 41. SSL 서버 자격 증명을 만드는 동안 심각한 오류가 발생했습니다.
514정성태7/14/200720866Team Foundation Server: 19. Orcas에서 개선되는 TFS 기능들
513정성태7/4/200731837.NET Framework: 91. Foreground Thread / Background Thread [1]
512정성태6/27/200721738오류 유형: 40. error PRJ0050: Failed to register output.
511정성태6/25/200729802.NET Framework: 90. XmlSerializer 생성자의 실행 속도를 올리는 방법 [2]
... 166  167  168  169  170  171  172  173  174  175  176  177  [178]  179  180  ...