예제 #1
0
        public void Apply(ActionModel action)
        {
            Produces(action);

            if (action.Is(HttpMethod.Get))
            {
                if (action.ActionName.Equals(Constants.GetById, StringComparison.OrdinalIgnoreCase))
                {
                    // invalid id:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status400BadRequest);

                    // resource not found:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status404NotFound);

                    if (action.Controller.ControllerType.IsGenericType && action.Controller.ControllerType.AsType().ImplementsGeneric(typeof(ResourceController <>)))
                    {
                        var controllerType = action.Controller.ControllerType.GetGenericArguments()[0];

                        // get resource by ID with return=representation:
                        action.ProducesResponseType(controllerType, StatusCodes.Status200OK);
                    }
                }

                if (action.ActionName.Equals(Constants.Get, StringComparison.OrdinalIgnoreCase) || action.ActionName.Equals(Constants.GetEmbedded, StringComparison.OrdinalIgnoreCase))
                {
                    if (action.Controller.ControllerType.IsGenericType && action.Controller.ControllerType.AsType().ImplementsGeneric(typeof(ResourceController <>)))
                    {
                        var controllerType = action.Controller.ControllerType.GetGenericArguments()[0];

                        // FIXME: @nextLink, @deltaLink, should be present, too
                        var collectionType = typeof(Many <>).MakeGenericType(controllerType);

                        // get resource collection with return=representation:
                        action.ProducesResponseType(collectionType, StatusCodes.Status200OK);

                        // get resource collection specifying a $top operator larger than the server maximum
                        action.ProducesResponseType <ProblemDetails>(StatusCodes.Status413PayloadTooLarge);
                    }
                }

                if (action.ActionName.Equals(Constants.GetNextPage, StringComparison.OrdinalIgnoreCase))
                {
                    if (action.Controller.ControllerType.IsGenericType && action.Controller.ControllerType.AsType().ImplementsGeneric(typeof(ResourceController <>)))
                    {
                        var controllerType = action.Controller.ControllerType.GetGenericArguments()[0];

                        // FIXME: @nextLink, @deltaLink, should be present, too
                        var collectionType = typeof(Many <>).MakeGenericType(controllerType);

                        // get resource collection with return=representation:
                        action.ProducesResponseType(collectionType, StatusCodes.Status200OK);
                    }
                }

                if (!action.HasAttribute <DoNotHttpCacheAttribute>())
                {
                    action.ProducesResponseType(StatusCodes.Status304NotModified);
                }
            }

            if (action.Is(HttpMethod.Post))
            {
                Consumes(action);

                if (action.ActionName.Equals(Constants.Create, StringComparison.OrdinalIgnoreCase))
                {
                    // created resource with return=minimal:
                    action.ProducesResponseType(StatusCodes.Status201Created);

                    // tried to create a resource that already exists, and the supplied resource was equivalent:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status303SeeOther);

                    // client followed a redirect via 303 See Other, and retrieved the cacheable resource
                    action.ProducesResponseType(StatusCodes.Status200OK);

                    // invalid body
                    // tried to create a resource that already exists, and the supplied resource was not equivalent
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status400BadRequest);

                    // server failed to save resource:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status500InternalServerError);
                }

                if (!action.HasAttribute <DoNotHttpCacheAttribute>())
                {
                    action.ProducesResponseType(StatusCodes.Status412PreconditionFailed);
                }
            }

            if (action.Is(HttpMethod.Put))
            {
                Consumes(action);

                // updated resource with return=minimal:
                action.ProducesResponseType(StatusCodes.Status204NoContent);

                // successful update operation:
                action.ProducesResponseType(StatusCodes.Status200OK);
            }

            if (action.Is(HttpMethod.Patch))
            {
                // successful patch operation:
                if (action.Controller.ControllerType.IsGenericType && action.Controller.ControllerType.AsType().ImplementsGeneric(typeof(ResourceController <>)))
                {
                    var controllerType = action.Controller.ControllerType.GetGenericArguments()[0];

                    // patched resource by ID with return=representation:
                    action.ProducesResponseType(controllerType, StatusCodes.Status200OK);
                }

                // patched resource by ID with return=minimal:
                action.ProducesResponseType(StatusCodes.Status204NoContent);

                // resource not found:
                action.ProducesResponseType <ProblemDetails>(StatusCodes.Status404NotFound);

                // invalid patch operation (tried to modify a read-only field, etc.):
                action.ProducesResponseType <ProblemDetails>(StatusCodes.Status400BadRequest);

                switch (_options.Value.ApiFormats)
                {
                case ApiSupportedMediaTypes.None:
                    throw new NotSupportedException(_localizer.GetString("API must support at least one content format"));

                case ApiSupportedMediaTypes.ApplicationJson | ApiSupportedMediaTypes.ApplicationXml:
                    action.Consumes(ApiMediaTypeNames.Application.JsonMergePatch,
                                    ApiMediaTypeNames.Application.XmlMergePatch,
                                    ApiMediaTypeNames.Application.JsonPatchJson,
                                    ApiMediaTypeNames.Application.JsonPatchXml);
                    break;

                case ApiSupportedMediaTypes.ApplicationJson:
                    action.Consumes(ApiMediaTypeNames.Application.JsonMergePatch, ApiMediaTypeNames.Application.JsonPatchJson);
                    break;

                case ApiSupportedMediaTypes.ApplicationXml:
                    action.Consumes(ApiMediaTypeNames.Application.XmlMergePatch, ApiMediaTypeNames.Application.JsonPatchXml);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (action.Is(HttpMethod.Delete))
            {
                if (action.ActionName.Equals(Constants.DeleteById, StringComparison.OrdinalIgnoreCase))
                {
                    // deleted resource with return=minimal:
                    action.ProducesResponseType(StatusCodes.Status204NoContent);

                    // invalid id:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status400BadRequest);

                    // resource not found:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status404NotFound);

                    // resource already deleted:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status410Gone);

                    // server failed to delete resource:
                    action.ProducesResponseType <ProblemDetails>(StatusCodes.Status500InternalServerError);

                    if (action.Controller.ControllerType.IsGenericType && action.Controller.ControllerType.AsType().ImplementsGeneric(typeof(ResourceController <>)))
                    {
                        var controllerType = action.Controller.ControllerType.GetGenericArguments()[0];

                        // deleted resource by ID with return=representation:
                        action.ProducesResponseType(controllerType, StatusCodes.Status200OK);
                    }
                }

                if (!action.HasAttribute <DoNotHttpCacheAttribute>())
                {
                    action.ProducesResponseType(StatusCodes.Status412PreconditionFailed);
                }
            }

            foreach (var parameter in action.Parameters)
            {
                Apply(parameter);
            }
        }