ASPNET MVC 인 터 럽 트 요청

30100 단어 asp
ASPNET MVC 는 어떻게 정확하게 요청 을 중단 합 니까?
그런 것 같은 데?
aspnet 개발 과정 에서 현재 http 처 리 를 중단 하려 면 이전 에는 aspnet 에서 Response. End () 였 습 니 다.
이 Response. End () 이후 현재 요청 한 코드 가 실행 되 지 않 습 니 다.
그러나 aspnetmvc 에 서 는 Response. End () 를 호출 하 더 라 도;그래도 실행!!
          //aspnet webform

            if(ok)

                Response.End();

            //save      

            Save();



            //aspnet mvc

            if (ok)

                Response.End();



            //save     

            Save();    

 
 aspnetmvc action 은 어떻게 간단하게 처리 합 니까?
액 션 에서 의 논리 가 중단 되 어야 한다 면 논리 적 판단 을 통 해 중단 할 수 있 습 니 다.
예 를 들 면:
if(ok) { //     

} else { //   

} //  



if(!ok) return Content("NO");

 근 데 필터 에 있 으 면!
        protected virtual void OnActionExecuted(ActionExecutedContext filterContext);

        protected virtual void OnActionExecuting(ActionExecutingContext filterContext);

        protected virtual void OnAuthorization(AuthorizationContext filterContext);

        protected virtual void OnException(ExceptionContext filterContext);

        protected virtual void OnResultExecuted(ResultExecutedContext filterContext);

        protected virtual void OnResultExecuting(ResultExecutingContext filterContext);

당신 의 논리 적 판단 과 Response. End (); 다 무효 야!
 나 는 많은 사람들 이 뛰 는 것 을 보 았 다!aspnet mvc 웹 api 라면 어디로 뛰 어 갑 니까?뭐 공부 해요?
정확 한 aspnet mvc filter 실행 자 세 를 취소!
바로 할당 입 니 다. filterContext.Result!
예 를 들 어 OnAction Executing
  protected override void OnActionExecuting(ActionExecutingContext filterContext) { var headerAuth = filterContext.HttpContext.Request.Headers["_applogin_"]; if (string.IsNullOrEmpty(headerAuth)) { filterContext.Result = new ContentResult() { Content = "{code:9999,message:'no login'}", ContentEncoding = Encoding.UTF8 }; } base.OnActionExecuting(filterContext); } }

 
왜 Context. Result 를 할당 하면 뒤의 필터 와 action 코드 를 계속 실행 하지 않 습 니까?
먼저 aspnetmvc 소스 코드 를 보 세 요!
aspnet mvc 소스 코드: ControllerActionInvoker. cs
using Microsoft.Web.Infrastructure.DynamicValidationHelper;

using System;

using System.Collections.Generic;

using System.Globalization;

using System.Linq;

using System.Threading;

using System.Web.Mvc.Properties;

namespace System.Web.Mvc

{

	/// <summary>Represents a class that is responsible for invoking the action methods of a controller.</summary>

	public class ControllerActionInvoker : IActionInvoker

	{

		private static readonly ControllerDescriptorCache _staticDescriptorCache = new ControllerDescriptorCache();

		private ModelBinderDictionary _binders;

		private Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk = new Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>>(FilterProviders.Providers.GetFilters);

		private ControllerDescriptorCache _instanceDescriptorCache;

		/// <summary>Gets or sets the model binders that are associated with the action.</summary>

		/// <returns>The model binders that are associated with the action.</returns>

		protected internal ModelBinderDictionary Binders

		{

			get

			{

				if (this._binders == null)

				{

					this._binders = ModelBinders.Binders;

				}

				return this._binders;

			}

			set

			{

				this._binders = value;

			}

		}

		internal ControllerDescriptorCache DescriptorCache

		{

			get

			{

				if (this._instanceDescriptorCache == null)

				{

					this._instanceDescriptorCache = ControllerActionInvoker._staticDescriptorCache;

				}

				return this._instanceDescriptorCache;

			}

			set

			{

				this._instanceDescriptorCache = value;

			}

		}

		/// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.ControllerActionInvoker" /> class.</summary>

		public ControllerActionInvoker()

		{

		}

		internal ControllerActionInvoker(params object[] filters) : this()

		{

			if (filters != null)

			{

				this._getFiltersThunk = ((ControllerContext cc, ActionDescriptor ad) => 

					from f in filters

					select new Filter(f, FilterScope.Action, null));

			}

		}

		/// <summary>Creates the action result.</summary>

		/// <returns>The action result object.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="actionDescriptor">The action descriptor.</param>

		/// <param name="actionReturnValue">The action return value.</param>

		protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)

		{

			if (actionReturnValue == null)

			{

				return new EmptyResult();

			}

			ActionResult arg_2B_0;

			if ((arg_2B_0 = (actionReturnValue as ActionResult)) == null)

			{

				arg_2B_0 = new ContentResult

				{

					Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture)

				};

			}

			return arg_2B_0;

		}

		/// <summary>Retrieves information about the controller by using the specified controller context.</summary>

		/// <returns>Information about the controller.</returns>

		/// <param name="controllerContext">The controller context.</param>

		protected virtual ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)

		{

			Type controllerType = controllerContext.Controller.GetType();

			return this.DescriptorCache.GetDescriptor(controllerType, () => new ReflectedControllerDescriptor(controllerType));

		}

		/// <summary>Finds the information about the action method.</summary>

		/// <returns>Information about the action method.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="controllerDescriptor">The controller descriptor.</param>

		/// <param name="actionName">The name of the action.</param>

		protected virtual ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)

		{

			return controllerDescriptor.FindAction(controllerContext, actionName);

		}

		/// <summary>Retrieves information about the action filters.</summary>

		/// <returns>Information about the action filters.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="actionDescriptor">The action descriptor.</param>

		protected virtual FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)

		{

			return new FilterInfo(this._getFiltersThunk(controllerContext, actionDescriptor));

		}

		private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor)

		{

			return parameterDescriptor.BindingInfo.Binder ?? this.Binders.GetBinder(parameterDescriptor.ParameterType);

		}

		/// <summary>Gets the value of the specified action-method parameter.</summary>

		/// <returns>The value of the action-method parameter.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="parameterDescriptor">The parameter descriptor.</param>

		protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)

		{

			Type parameterType = parameterDescriptor.ParameterType;

			IModelBinder modelBinder = this.GetModelBinder(parameterDescriptor);

			IValueProvider valueProvider = controllerContext.Controller.ValueProvider;

			string modelName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;

			Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor);

			ModelBindingContext bindingContext = new ModelBindingContext

			{

				FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null,

				ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),

				ModelName = modelName,

				ModelState = controllerContext.Controller.ViewData.ModelState,

				PropertyFilter = propertyFilter,

				ValueProvider = valueProvider

			};

			object obj = modelBinder.BindModel(controllerContext, bindingContext);

			return obj ?? parameterDescriptor.DefaultValue;

		}

		/// <summary>Gets the values of the action-method parameters.</summary>

		/// <returns>The values of the action-method parameters.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="actionDescriptor">The action descriptor.</param>

		protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)

		{

			Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

			ParameterDescriptor[] parameters = actionDescriptor.GetParameters();

			ParameterDescriptor[] array = parameters;

			for (int i = 0; i < array.Length; i++)

			{

				ParameterDescriptor parameterDescriptor = array[i];

				dictionary[parameterDescriptor.ParameterName] = this.GetParameterValue(controllerContext, parameterDescriptor);

			}

			return dictionary;

		}

		private static Predicate<string> GetPropertyFilter(ParameterDescriptor parameterDescriptor)

		{

			ParameterBindingInfo bindingInfo = parameterDescriptor.BindingInfo;

			return (string propertyName) => BindAttribute.IsPropertyAllowed(propertyName, bindingInfo.Include.ToArray<string>(), bindingInfo.Exclude.ToArray<string>());

		}

		/// <summary>Invokes the specified action by using the specified controller context.</summary>

		/// <returns>The result of executing the action.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="actionName">The name of the action to invoke.</param>

		/// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext" /> parameter is null.</exception>

		/// <exception cref="T:System.ArgumentException">The <paramref name="actionName" /> parameter is null or empty.</exception>

		/// <exception cref="T:System.Threading.ThreadAbortException">The thread was aborted during invocation of the action.</exception>

		/// <exception cref="T:System.Exception">An unspecified error occurred during invocation of the action.</exception>

		public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)

		{

			if (controllerContext == null)

			{

				throw new ArgumentNullException("controllerContext");

			}

			if (string.IsNullOrEmpty(actionName))

			{

				throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");

			}

			ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);

			ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);

			if (actionDescriptor != null)

			{

				FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);

				try

				{

					AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);

					if (authorizationContext.Result != null)

					{

						this.InvokeActionResult(controllerContext, authorizationContext.Result);

					}

					else

					{

						if (controllerContext.Controller.ValidateRequest)

						{

							ControllerActionInvoker.ValidateRequest(controllerContext);

						}

						IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);

						ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);

						this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);

					}

				}

				catch (ThreadAbortException)

				{

					throw;

				}

				catch (Exception exception)

				{

					ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);

					if (!exceptionContext.ExceptionHandled)

					{

						throw;

					}

					this.InvokeActionResult(controllerContext, exceptionContext.Result);

				}

				return true;

			}

			return false;

		}

		/// <summary>Invokes the specified action method by using the specified parameters and the controller context.</summary>

		/// <returns>The result of executing the action method.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="actionDescriptor">The action descriptor.</param>

		/// <param name="parameters">The parameters.</param>

		protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)

		{

			object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);

			return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);

		}

		internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)

		{

			filter.OnActionExecuting(preContext);

			if (preContext.Result != null)

			{

				return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null)

				{

					Result = preContext.Result

				};

			}

			bool flag = false;

			ActionExecutedContext actionExecutedContext = null;

			try

			{

				actionExecutedContext = continuation();

			}

			catch (ThreadAbortException)

			{

				actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null);

				filter.OnActionExecuted(actionExecutedContext);

				throw;

			}

			catch (Exception exception)

			{

				flag = true;

				actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception);

				filter.OnActionExecuted(actionExecutedContext);

				if (!actionExecutedContext.ExceptionHandled)

				{

					throw;

				}

			}

			if (!flag)

			{

				filter.OnActionExecuted(actionExecutedContext);

			}

			return actionExecutedContext;

		}

		/// <summary>Invokes the specified action method by using the specified parameters, controller context, and action filters.</summary>

		/// <returns>The context for the ActionExecuted method of the <see cref="T:System.Web.Mvc.ActionFilterAttribute" /> class.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="filters">The action filters.</param>

		/// <param name="actionDescriptor">The action descriptor.</param>

		/// <param name="parameters">The parameters.</param>

		protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)

		{

			ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);

			Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)

			{

				Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)

			};

			Func<ActionExecutedContext> func = filters.Reverse<IActionFilter>().Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next));

			return func();

		}

		/// <summary>Invokes the specified action result by using the specified controller context.</summary>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="actionResult">The action result.</param>

		protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)

		{

			actionResult.ExecuteResult(controllerContext);

		}

		internal static ResultExecutedContext InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func<ResultExecutedContext> continuation)

		{

			filter.OnResultExecuting(preContext);

			if (preContext.Cancel)

			{

				return new ResultExecutedContext(preContext, preContext.Result, true, null);

			}

			bool flag = false;

			ResultExecutedContext resultExecutedContext = null;

			try

			{

				resultExecutedContext = continuation();

			}

			catch (ThreadAbortException)

			{

				resultExecutedContext = new ResultExecutedContext(preContext, preContext.Result, false, null);

				filter.OnResultExecuted(resultExecutedContext);

				throw;

			}

			catch (Exception exception)

			{

				flag = true;

				resultExecutedContext = new ResultExecutedContext(preContext, preContext.Result, false, exception);

				filter.OnResultExecuted(resultExecutedContext);

				if (!resultExecutedContext.ExceptionHandled)

				{

					throw;

				}

			}

			if (!flag)

			{

				filter.OnResultExecuted(resultExecutedContext);

			}

			return resultExecutedContext;

		}

		/// <summary>Invokes the specified action result by using the specified action filters and the controller context.</summary>

		/// <returns>The context for the ResultExecuted method of the <see cref="T:System.Web.Mvc.ActionFilterAttribute" /> class.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="filters">The action filters.</param>

		/// <param name="actionResult">The action result.</param>

		protected virtual ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult)

		{

			ResultExecutingContext preContext = new ResultExecutingContext(controllerContext, actionResult);

			Func<ResultExecutedContext> seed = delegate

			{

				this.InvokeActionResult(controllerContext, actionResult);

				return new ResultExecutedContext(controllerContext, actionResult, false, null);

			};

			Func<ResultExecutedContext> func = filters.Reverse<IResultFilter>().Aggregate(seed, (Func<ResultExecutedContext> next, IResultFilter filter) => () => ControllerActionInvoker.InvokeActionResultFilter(filter, preContext, next));

			return func();

		}

		/// <summary>Invokes the specified authorization filters by using the specified action descriptor and controller context.</summary>

		/// <returns>The context for the <see cref="T:System.Web.Mvc.AuthorizeAttribute" /> object.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="filters">The authorization filters.</param>

		/// <param name="actionDescriptor">The action descriptor.</param>

		protected virtual AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)

		{

			AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext, actionDescriptor);

			foreach (IAuthorizationFilter current in filters)

			{

				current.OnAuthorization(authorizationContext);

				if (authorizationContext.Result != null)

				{

					break;

				}

			}

			return authorizationContext;

		}

		/// <summary>Invokes the specified exception filters by using the specified exception and controller context.</summary>

		/// <returns>The context for the <see cref="T:System.Web.Mvc.HandleErrorAttribute" /> object.</returns>

		/// <param name="controllerContext">The controller context.</param>

		/// <param name="filters">The exception filters.</param>

		/// <param name="exception">The exception.</param>

		protected virtual ExceptionContext InvokeExceptionFilters(ControllerContext controllerContext, IList<IExceptionFilter> filters, Exception exception)

		{

			ExceptionContext exceptionContext = new ExceptionContext(controllerContext, exception);

			foreach (IExceptionFilter current in filters.Reverse<IExceptionFilter>())

			{

				current.OnException(exceptionContext);

			}

			return exceptionContext;

		}

		internal static void ValidateRequest(ControllerContext controllerContext)

		{

			if (controllerContext.IsChildAction)

			{

				return;

			}

			HttpContext current = HttpContext.Current;

			if (current != null)

			{

				ValidationUtility.EnableDynamicValidation(current);

			}

			controllerContext.HttpContext.Request.ValidateInput();

		}

	}

}


 간단 한 설명 을 첨부 합 니 다:
        /// <summary>

        ///           

        /// </summary>

        /// <param name="controllerContext"></param>

        /// <param name="actionName"></param>

        /// <returns></returns>

        public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)

        {

            if (controllerContext == null)

            {

                throw new ArgumentNullException("controllerContext");

            }

            if (string.IsNullOrEmpty(actionName))

            {

                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");

            }

            //          

            ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);

            //          action  

            ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);

            //action   

            if (actionDescriptor != null)

            {

                //       

                FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);

                try

                {

                    //  aspnetmvc   Authorization  

                    AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);



                    //        ,             ,          Result,        Result,action               

                    if (authorizationContext.Result != null)

                    {

                        this.InvokeActionResult(controllerContext, authorizationContext.Result);

                    }

                    else

                    {

                        //        

                        if (controllerContext.Controller.ValidateRequest)

                        {

                            ControllerActionInvoker.ValidateRequest(controllerContext);

                        }



                        //      

                        IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);

                        //       

                        ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);



                        //        action

                        this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);

                    }

                }

                catch (ThreadAbortException)

                {

                    throw;

                }

                catch (Exception exception)

                {

                    ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);

                    if (!exceptionContext.ExceptionHandled)

                    {

                        throw;

                    }

                    this.InvokeActionResult(controllerContext, exceptionContext.Result);

                }

                return true;

            }

            return false;

        }



        //      action



        // System.Web.Mvc.ControllerActionInvoker

        protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)

        {

            ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);

            Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)

            {

                //  action

                Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)

            };

            //  filters, active   seed   ,    filters     ActionExecutedContext



            //        ,              ,    active,          Context.Result,              active,

            Func<ActionExecutedContext> func = filters.Reverse<IActionFilter>()

                .Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) =>

                    () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next));

            return func();

        }



        // System.Web.Mvc.ControllerActionInvoker

        internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)

        {

            //  OnActionExecuting

            filter.OnActionExecuting(preContext);



            if (preContext.Result != null)

            {

                return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null)

                {

                    Result = preContext.Result

                };

            }

            bool flag = false;

            ActionExecutedContext actionExecutedContext = null;

            try

            {

                //     action

                actionExecutedContext = continuation();

            }

            catch (ThreadAbortException)

            {

                actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null);

                filter.OnActionExecuted(actionExecutedContext);

                throw;

            }

            catch (Exception exception)

            {

                flag = true;

                actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception);

                filter.OnActionExecuted(actionExecutedContext);

                if (!actionExecutedContext.ExceptionHandled)

                {

                    throw;

                }

            }

            if (!flag)

            {

                filter.OnActionExecuted(actionExecutedContext);

            }

            return actionExecutedContext;

        }


상기 코드 를 통 해 알 수 있 듯 이 하나의 action 의 실행 절 차 는 다음 과 같다.
 
1 > 요청 에 따라 Controller 와 action 의 정 보 를 가 져 옵 니 다.
2 > 있 을 필터 가 져 오기
3 > Authorization 인증, 통과 하지 않 으 면 되 돌려 줍 니 다.
4 > ValidateRequest, 요청 데이터 검증
5 > 필터 와 active 를 실행 합 니 다. 중간 에 필터 에 Result 가 발생 하면 뒤의 필터 와 active 는 실행 되 지 않 습 니 다!
 
그래서 가장 정확 한 방법 은 필터 에 Result 를 부여 하 는 것 입 니 다!

좋은 웹페이지 즐겨찾기