示例#1
0
        public ActionResult <IEnumerable <SongbookResult> > Post([FromBody] IEnumerable <SongbookCreate> songbookCollection)
        {
            if (songbookCollection == null)
            {
                return(BadRequest());
            }

            _logger.LogDebug("SongbookCollectionController.Post called to add a new collection of songbooks {@songbookCollection}", songbookCollection);
            var songbooks = _mapper.Map <IEnumerable <SongbookDto> >(songbookCollection).Select(Songbook.From).ToList();

            //Perform validation
            foreach (var songbook in songbooks)
            {
                if (!songbook.IsValid)
                {
                    songbook.Validate().AddToModelState(ModelState, $"({songbook.Title})");
                    _logger.LogWarning("{method} failed model validation (ModelState: {@modelState}), returning Unprocessable Entity", nameof(Post), ModelState.Values.SelectMany(v => v.Errors));
                }
            }
            if (!ModelState.IsValid)
            {
                return(InvalidModelStateResponseFactory.GenerateResponseForInvalidModelState(ModelState, HttpContext));
            }

            foreach (var songbook in songbooks)
            {
                _repository.Save(songbook);
            }

            var idsAsString = string.Join(",", songbooks.Select(sb => sb.Id));

            return(CreatedAtRoute("GetSongbookCollection", new { ids = idsAsString }, _mapper.Map <IEnumerable <SongbookResult> >(songbooks).Select(CreateLinksForSongbook)));
        }
示例#2
0
        public ActionResult <SongResult> Post(Guid songbookId, [FromBody] SongCreate song)
        {
            if (song == null)
            {
                return(BadRequest());
            }

            _logger.LogDebug("SongController.Post called to create new song for songbook {@songbookId}: {@songbook}", songbookId, song);
            var songbook = _repository.GetById(songbookId);

            if (songbook == null)
            {
                _logger.LogWarning("Songbook.Post failed to add song {@song} to songbook {@songbookId}. Songbook was not found.", song, songbookId);
                return(NotFound());
            }

            var dto     = _mapper.Map <SongDto>(song);
            var newSong = Song.From(dto);

            //Perform validation
            if (!newSong.IsValid)
            {
                newSong.Validate().AddToModelState(ModelState, null);
                _logger.LogWarning("{method} failed model validation (ModelState: {@modelState}), returning Unprocessable Entity", nameof(Post), ModelState.Values.SelectMany(v => v.Errors));
                return(InvalidModelStateResponseFactory.GenerateResponseForInvalidModelState(ModelState, HttpContext));
            }

            songbook.Songs.Add(newSong);

            _repository.Save(songbook);

            return(CreatedAtRoute("GetSong", new { songbookId = newSong.SongbookId, id = newSong.Id }, newSong));
        }
        public ActionResult <SongbookResult> Post([FromBody] SongbookCreate songbook)
        {
            if (songbook == null)
            {
                return(BadRequest());
            }

            _logger.LogDebug("SongbookController.Post called to create new songbook: {@songbook}", songbook);
            var dto         = _mapper.Map <SongbookDto>(songbook);
            var newSongbook = Songbook.From(dto);

            //Perform validation
            if (!newSongbook.IsValid)
            {
                newSongbook.Validate().AddToModelState(ModelState, null);
                _logger.LogWarning("{method} failed model validation (ModelState: {@modelState}), returning Unprocessable Entity", nameof(Post), ModelState.Values.SelectMany(v => v.Errors));
                return(InvalidModelStateResponseFactory.GenerateResponseForInvalidModelState(ModelState, HttpContext));
            }

            _repository.Save(newSongbook);

            return(CreatedAtRoute("GetSongbook", new { id = newSongbook.Id }, newSongbook));
        }
示例#4
0
 public override BadRequestObjectResult BadRequest(ModelStateDictionary modelState)
 => InvalidModelStateResponseFactory.CreateFrom("InvalidModel", modelState);
示例#5
0
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpCacheHeaders((expirationModelOptions) =>
            {
                expirationModelOptions.MaxAge        = 600;
                expirationModelOptions.CacheLocation = Marvin.Cache.Headers.CacheLocation.Private;
            },
                                         (validationModelOptions) =>
            {
                validationModelOptions.MustRevalidate = true;
            });

            services.AddControllers()
            .ConfigureApiBehaviorOptions(setupAction =>
            {
                setupAction.InvalidModelStateResponseFactory = context =>
                {
                    return(InvalidModelStateResponseFactory.GenerateResponseForInvalidModelState(context.ModelState, context.HttpContext));
                };
            });

            services.AddMvc(setupAction =>
            {
                //Return 406 'Not Acceptable' for any unsupported media types
                setupAction.ReturnHttpNotAcceptable = true;

                //Create default response types for all controllers
                setupAction.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status400BadRequest));
                setupAction.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status406NotAcceptable));
                setupAction.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status500InternalServerError));
            }).AddFluentValidation(setupAction =>
            {
                setupAction.RunDefaultMvcValidationAfterFluentValidationExecutes = true;
            });

            services.AddSingleton <ISongDao, SongDao>();
            services.AddSingleton <ISongbookDao, SongbookDao>();
            services.AddSingleton <ICreatorDao, CreatorDao>();
            services.AddSingleton <ISongbookRepository, SongbookRepository>();

            services.AddSingleton <IActionContextAccessor, ActionContextAccessor>();

            services.AddTransient <IPropertyMappingService, PropertyMappingService>();

            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton <IRateLimitConfiguration, RateLimitConfiguration>();
            services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
            services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>();

            var mappingConfig = new MapperConfiguration(mc =>
            {
                mc.AddProfile(new SongbookProfile());
                mc.AddProfile(new CreatorProfile());
                mc.AddProfile(new SongProfile());
                mc.AddProfile(new ParametersProfile());
            });

            IMapper mapper = mappingConfig.CreateMapper();

            services.AddSingleton(mapper);

            services.AddSwaggerGen(setupAction =>
            {
                setupAction.SwaggerDoc("HymnstagramOpenAPISpecification", new Microsoft.OpenApi.Models.OpenApiInfo()
                {
                    Title       = "Library API",
                    Description = "Create, read, and delete songbooks and songs your congregation uses.",
                    Contact     = new Microsoft.OpenApi.Models.OpenApiContact()
                    {
                        Email = "*****@*****.**",
                        Name  = "Hymnstagram Development",
                        Url   = new Uri("https://www.hymnstagram.com")
                    },
                    License = new Microsoft.OpenApi.Models.OpenApiLicense()
                    {
                        Name = "MIT License",
                        Url  = new Uri("https://opensource.org/licenses/MIT")
                    },
                    //TermsOfService = new Uri(""),
                    Version = "1"
                });

                var xmlCommentsFile     = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlCommentsFullPath = Path.Combine(AppContext.BaseDirectory, xmlCommentsFile);
                setupAction.IncludeXmlComments(xmlCommentsFullPath);
            });

            services.AddMemoryCache();

            services.Configure <IpRateLimitOptions>((options) =>
            {
                options.GeneralRules = new List <RateLimitRule>()
                {
                    new RateLimitRule()
                    {
                        Endpoint = "*",
                        Limit    = 50,
                        Period   = "5m"
                    }
                };
            });
        }