소스 오픈 - ASP를 읽어드릴게요.NET_MVC(13)

오늘은 전편의 진도에 이어 Model Binding에 대해 계속 토론하겠습니다.
연결이 원활하기 위해서 전편의 마지막 코드를 다시 한 번 붙여라. 우선 코드 단락 1이라고 부른다.
 
       protected virtual objectGetParameterValue(ControllerContext controllerContext, ParameterDescriptorparameterDescriptor)
        {
            // collect all of the necessarybinding properties
            Type parameterType =parameterDescriptor.ParameterType;
            IModelBinder binder =GetModelBinder(parameterDescriptor);
            IValueProvider valueProvider =controllerContext.Controller.ValueProvider;
            string parameterName =parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
            Predicate<string>propertyFilter = GetPropertyFilter(parameterDescriptor);
 
            // finally, call into the binder
            ModelBindingContext bindingContext= new ModelBindingContext()
            {
                FallbackToEmptyPrefix =(parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefixnot specified
                ModelMetadata =ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
                ModelName = parameterName,
                ModelState =controllerContext.Controller.ViewData.ModelState,
                PropertyFilter =propertyFilter,
                ValueProvider = valueProvider
            };
 
            object result =binder.BindModel(controllerContext, bindingContext);
            return result ??parameterDescriptor.DefaultValue;
        }

코드 세그먼트 1
여기서 관건은 두 가지를 분명히 해야 한다. 첫째, MVC가 IModel Binder 인터페이스의 실례를 어떻게 얻는가, 둘째, 이 인터페이스의 Bind Model 방법은 Request 관련 정보를 상응하는 모델 위에 어떻게 연결하는가이다.
첫 번째 점을 보고 코드 세그먼트 1에서 GetModelBinder 방법의 호출을 찾아 F12를 누르면 정의에 들어갑니다(코드 세그먼트 2).이 방법은'//look on the parameter itself, then look in the global table'이라는 주석과 결합하면 MVC가 먼저 들어오는parameter Descriptor를 검사한다는 것을 알 수 있다.BindingInfo.Binder가 비어 있는지 여부, 비어 있지 않으면 이 속성을 되돌려줍니다. 비어 있으면 Binders를 호출합니다.GetBinder 메서드, 글로벌 테이블에서 IModelBinder를 찾습니다.
        private IModelBinderGetModelBinder(ParameterDescriptor parameterDescriptor)
        {
            // look on the parameter itself,then look in the global table
            returnparameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);
        }

코드 세그먼트 2
Binders로 들어가기GetBinder 메서드의 정의입니다. 리셋이 많아서 최종 호출된 버전 (코드 세그먼트 3) 을 직접 찾을 수 있습니다.
        private IModelBinder GetBinder(TypemodelType, IModelBinder fallbackBinder)
        {
            // Try to look up a binder for thistype. We use this order of precedence:
            // 1. Binder returned from provider
            // 2. Binder registered in theglobal table
            // 3. Binder attribute defined onthe type
            // 4. Supplied fallback binder
 
            IModelBinder binder =_modelBinderProviders.GetBinder(modelType);
            if (binder != null)
            {
                return binder;
            }
 
            if(_innerDictionary.TryGetValue(modelType, out binder))
            {
                return binder;
            }
 
            // Function is called frequently,so ensure the error delegate is stateless
            binder =ModelBinders.GetBinderFromAttributes(modelType, (Type errorModel) =>
                {
                    throw new InvalidOperationException(
                       String.Format(CultureInfo.CurrentCulture,MvcResources.ModelBinderDictionary_MultipleAttributes, errorModel.FullName));
                });
 
            return binder ?? fallbackBinder;
        }

코드 세그먼트 3
마이크로소프트의 소스 오픈 프로젝트 그룹은 여전히 코드 주석을 비교적 중시하는데, 이 방법은 처음에 상당히 깔끔한 주석이었다.비록 여러분의 영어는 모두 상당한 NB이지만, 저는 추태를 보여 번역을 하겠습니다.
이 종류의binder를 찾아보십시오.다음과 같은 순서로 검색했습니다.
1. provider가 반환하는 Binder
2. 글로벌 리스트에 등록된 Binder
3. 이 유형에 정의된 Binder 특성
4. 사용자가 제공하는 예비 Binder
다음은 이 네 개의 실현 원리를 조목조목 토론한다.
1. provider가 반환하는 Binder.
다음 문을 찾습니다.
        IModelBinderbinder = _modelBinderProviders.GetBinder(modelType);
모델 Binder Providers라는 개인 구성원이 어떻게 값을 부여하는지 보고, 그 클래스인 모델 Binder Dictionary의 구조 함수 (코드 세그먼트 4) 를 찾아봅시다.
        public ModelBinderDictionary()
            :this(ModelBinderProviders.BinderProviders)
        {
        }
 
        internal ModelBinderDictionary(ModelBinderProviderCollectionmodelBinderProviders)
        {
            _modelBinderProviders =modelBinderProviders;
        }

코드 세그먼트 4
모델 Binder Providers는 모델 Binder Providers를 사용합니다.BinderProviders는 값을 부여하고 ModelBinderProviders는 값을 부여합니다.Binder Providers[1]는 또 뭐죠?우리는 코드 세그먼트 5를 보았는데, 이것은 우리가 자신의 MVC 프로젝트에서 글로벌한 것이다.asax 파일의 Application이 방법 중 두 번째 문장(//*곳)은 우리가 사용자 정의의 mModel Binder Provider를 Model Binder Provider에 추가하는 것이다.Binder Providers 집합에서 이 집합은 위에 표시된 [1] 곳의 그 어떤 것이다.
protected voidApplication_Start()
{
AreaRegistration.RegisterAllAreas();
 
ModelBinderProviders.BinderProviders.Add(newCustomModelBinderProvider());//*
 
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

코드 세그먼트 5
2. 글로벌 리스트에 등록된 Binder.
이것은 비교적 간단합니다. 코드 [innerDictionary.TryGetValue(modelType,out binder)]입니다. 그 중에서 innerDictionary는 사전의 대상입니다. 이 사전에서 이 유형의 Binder를 찾는 것을 의미합니다.
3. 이 유형에 정의된 Binder 특성.
코드 세그먼트 3에서 ModelBinders를 찾습니다.GetBinder From Attributes 방법은 이름에서 Attributes에서 Binder를 가져오는 역할을 추측할 수 있습니다.다음은 정의 (코드 세그먼트 6) 로 이동합니다. 이 코드는 GetAttributes () 를 통해 형식 type의 모든 특성 (Attributes) 을 가져오고, Single OfType Default OrError 방법을 호출하여 사용자 정의의Custom Model Binder Attribute를 가져오고, 마지막으로 GetBinder 방법을 호출하여 IMode Binder를 가져와서 되돌려줍니다.
       internal static IModelBinder GetBinderFromAttributes(Type type,Action<Type> errorAction)
       {
           AttributeList allAttrs = newAttributeList(TypeDescriptorHelper.Get(type).GetAttributes());
           CustomModelBinderAttributebinder = allAttrs.SingleOfTypeDefaultOrError<Attribute,CustomModelBinderAttribute, Type>(errorAction, type);
           return binder == null ? null : binder.GetBinder();
       }

코드 세그먼트 6
Single OfType Default OrError 방법의 정의는 코드 세그먼트 7을 보십시오. 이것은 IList 일반 클래스의 확장 방법입니다. 이것은 IList 집합에서 TMatch의 요소를 검색하는 데 작용합니다. 집합에 일치하는 요소만 있으면 이 요소를 되돌려줍니다.일치하지 않으면 공백으로 되돌아오기;하나 이상의 일치가 있으면, 리셋 의뢰 error Action을 호출합니다.
       /// <summary>
       /// Returns a single value in list matching type TMatch if there is onlyone, null if there are none of type TMatch or calls the
       /// errorAction with errorArg1 if there is more than one.
       /// </summary>
       public static TMatch SingleOfTypeDefaultOrError<TInput, TMatch,TArg1>(this IList<TInput> list, Action<TArg1> errorAction, TArg1errorArg1) where TMatch : class
       {
           Contract.Assert(list != null);
           Contract.Assert(errorAction != null);
 
           TMatch result = null;
           for (int i = 0; i < list.Count; i++)
           {
                TMatch typedValue = list[i] asTMatch;
                if (typedValue != null)
                {
                    if (result == null)
                    {
                        result = typedValue;
                    }
                    else
                    {
                        errorAction(errorArg1);
                        return null;
                    }
                }
           }
           return result;
       }

코드 세그먼트 7

좋은 웹페이지 즐겨찾기