public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var actionContext = GetActionContext(contentBytes, contentType: requestContentType); var formatterContext = new InputFormatterContext(actionContext, typeof(string)); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); var formatterContext = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, modelType: typeof(string)); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.Configure <MvcOptions>(options => { options.InputFormatters.Clear(); var jsonInputFormatter = new JsonInputFormatter(); jsonInputFormatter.SupportedMediaTypes.Clear(); jsonInputFormatter.SupportedMediaTypes.Add(JsonMediaType); options.InputFormatters.Add(jsonInputFormatter); var xmlSerializerInputFormatter = new XmlSerializerInputFormatter(); xmlSerializerInputFormatter.SupportedMediaTypes.Clear(); xmlSerializerInputFormatter.SupportedMediaTypes.Add(XmlSerializerMediaType); options.InputFormatters.Add(xmlSerializerInputFormatter); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Clear(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add(XmlDataContractSerializerMediaType); options.InputFormatters.Add(xmlDataContractSerializerInputFormatter); options.OutputFormatters.Clear(); var jsonOutputFormatter = new JsonOutputFormatter(); jsonOutputFormatter.SupportedMediaTypes.Clear(); jsonOutputFormatter.SupportedMediaTypes.Add(JsonMediaType); options.OutputFormatters.Add(jsonOutputFormatter); var xmlSerializerOutputFormatter = new XmlSerializerOutputFormatter(); xmlSerializerOutputFormatter.SupportedMediaTypes.Clear(); xmlSerializerOutputFormatter.SupportedMediaTypes.Add(XmlSerializerMediaType); options.OutputFormatters.Add(xmlSerializerOutputFormatter); var xmlDataContractSerializerOutputFormatter = new XmlDataContractSerializerOutputFormatter(); xmlDataContractSerializerOutputFormatter.SupportedMediaTypes.Clear(); xmlDataContractSerializerOutputFormatter.SupportedMediaTypes.Add(XmlDataContractSerializerMediaType); options.OutputFormatters.Add(xmlDataContractSerializerOutputFormatter); }); }
public async Task SuppressInputFormatterBufferingSetToTrue_UsingMutatedOptions() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var mvcOptions = new MvcOptions() { SuppressInputFormatterBuffering = false }; var formatter = new XmlDataContractSerializerInputFormatter(mvcOptions); var contentBytes = Encoding.UTF8.GetBytes(input); var httpContext = new DefaultHttpContext(); httpContext.Features.Set <IHttpResponseFeature>(new TestResponseFeature()); httpContext.Request.Body = new NonSeekableReadStream(contentBytes); httpContext.Request.ContentType = "application/xml"; var context = GetInputFormatterContext(httpContext, typeof(TestLevelOne)); // Act // Mutate options after passing into the constructor to make sure that the value type is not store in the constructor mvcOptions.SuppressInputFormatterBuffering = true; var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType <TestLevelOne>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.sampleString); // Reading again should fail as buffering request body is disabled await Assert.ThrowsAsync <XmlException>(() => formatter.ReadAsync(context)); }
public async Task ReadAsync_ReadsWhenConfiguredWithKnownTypes() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var KnownTypeName = "SomeDummyClass"; var InstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; var input = string.Format( CultureInfo.InvariantCulture, "<DummyClass i:type=\"{0}\" xmlns:i=\"{1}\"><SampleInt>{2}</SampleInt>" + "<SampleString>{3}</SampleString></DummyClass>", KnownTypeName, InstanceNamespace, expectedInt, expectedString); var settings = new DataContractSerializerSettings { KnownTypes = new[] { typeof(SomeDummyClass) } }; var formatter = new XmlDataContractSerializerInputFormatter(new MvcOptions()) { SerializerSettings = settings }; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType <SomeDummyClass>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.SampleString); }
public async Task ReadAsync_ReadsWhenMaxDepthIsModified() { // Arrange var expectedInt = 10; var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<DummyClass><SampleInt>" + expectedInt + "</SampleInt></DummyClass>"; var formatter = new XmlDataContractSerializerInputFormatter(new MvcOptions()); formatter.MaxDepth = 10; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType <DummyClass>(result.Model); Assert.Equal(expectedInt, model.SampleInt); }
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); var provider = new EmptyModelMetadataProvider(); var metadata = provider.GetMetadataForType(typeof(string)); var formatterContext = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, metadata: metadata, readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); var provider = new EmptyModelMetadataProvider(); var metadata = provider.GetMetadataForType(typeof(string)); var formatterContext = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, metadata: metadata, readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
private void ConfigureOutputFormatters(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; // Add XML Data contract serializer setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }).AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); }
public async Task ReadAsync_ReadsWhenConfiguredWithRootName() { // Arrange var expectedInt = 10; var SubstituteRootName = "SomeOtherClass"; var SubstituteRootNamespace = "http://tempuri.org"; var input = string.Format( CultureInfo.InvariantCulture, "<{0} xmlns=\"{1}\"><SampleInt xmlns=\"\">{2}</SampleInt></{0}>", SubstituteRootName, SubstituteRootNamespace, expectedInt); var dictionary = new XmlDictionary(); var settings = new DataContractSerializerSettings { RootName = dictionary.Add(SubstituteRootName), RootNamespace = dictionary.Add(SubstituteRootNamespace) }; var formatter = new XmlDataContractSerializerInputFormatter(new MvcOptions()) { SerializerSettings = settings }; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType <DummyClass>(result.Model); Assert.Equal(expectedInt, model.SampleInt); }
private static void SetupMvcOptions(MvcOptions setupAction) { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); XmlDataContractSerializerInputFormatter xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add( "application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); JsonOutputFormatter jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); jsonOutputFormatter?.SupportedMediaTypes.Add(VendorMediaType); JsonInputFormatter jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); jsonInputFormatter?.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); jsonInputFormatter?.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+json"); }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.Unicode.GetBytes(input); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16"); var provider = new EmptyModelMetadataProvider(); var metadata = provider.GetMetadataForType(typeof(TestLevelOne)); var context = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, metadata: metadata, readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType <TestLevelOne>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.sampleString); }
public async Task PostingModelOfStructs_WithDeeperHierarchy_HasValidationErrors() { // Arrange var input = "<School i:nil=\"true\" " + "xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\" " + "xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"/>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(School)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.Null(model); Assert.Equal(3, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(School).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(School.Id), typeof(School).FullName) }); AssertModelStateErrorMessages( typeof(Website).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Website.Id), typeof(Website).FullName) }); AssertModelStateErrorMessages( typeof(Student).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Student.Id), typeof(Student).FullName) }); }
public void ConfigureServices(IServiceCollection services) { services.AddMvc( setupAction => { setupAction.ReturnHttpNotAcceptable = true; // Force consumer to specify data format setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // Support returning XML setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); // Support incoming XML // Versioning support for date of demise with XML var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.companywithdateofdemise.full+xml"); // Don't bother adding support for XML for v3 setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); // Versioning support for date of demise with JSON var jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.company.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.companywithdateofdemise.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.companywithlocation.full+json"); } // Use custom media type to support HATEOAS var jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }).AddJsonOptions( options => { // Prevent property name casing from being lost on serialization of JSON requests options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // Approach using a DB Context (for fast development). // https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/ // Add-Migration InitialCreate or dotnet ef migrations add InitialCreate // Update-Database or dotnet ef database update // Add-Migration AddDateOfDemise or dotnet ef migrations add AddDateOfDemise // TODO - Move connection string to environment variable var connectionString = Configuration["connectionStrings:dbConnectionString"]; services.AddDbContext <RepositoryContext>(context => context.UseSqlServer(connectionString)); //services.AddScoped<IRepository, MockRepository>(); services.AddScoped <IRepository, EntityFrameworkRepository>(); // Register URI helper to support metadata in responses services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>( implementationFactory => { return(new UrlHelper(actionContext: implementationFactory.GetService <IActionContextAccessor>().ActionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); // Custom service to support sorting services.AddTransient <ITypeHelperService, TypeHelperService>(); // Custom service to support data shaping // Caching support for consumer using HTTP cache headers from Marvin services.AddHttpCacheHeaders( (expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, // expiration caching (validationModelOptions) => { validationModelOptions.MustRevalidate = true; }); // validation caching services.AddResponseCaching(); // MS .Net core package for response caching. Doesn't generate response headers. Buggy before v2. Not ideal! // Implement throttling // Can throttle by IP and / or by client. // Can throttle by calls to specific controllers or methods // Can throttle by (for example); requests per day, requests per hour, and requests per controller. // Request headers for this are; X-Rate-Limit-Limit, X-Rate-Limit-Remaining, and X-Rate-Limit-Reset. // Disallowed requests will return a 429 response with an optional Retry-After header and a body explaining the condition. services.AddMemoryCache(); // Used to store throttling counters and rules services.Configure <IpRateLimitOptions>( options => { options.GeneralRules = new List <RateLimitRule> { new RateLimitRule // 10 requests every 5 minutes { Endpoint = "*", Limit = 10, Period = "5m" }, new RateLimitRule // 2 requests every 10 seconds { Endpoint = "*", Limit = 2, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
public void HasProperSuppportedEncodings() { // Arrange & Act var formatter = new XmlDataContractSerializerInputFormatter(); // Assert Assert.True(formatter.SupportedEncodings.Any(i => i.WebName == "utf-8")); Assert.True(formatter.SupportedEncodings.Any(i => i.WebName == "utf-16")); }
public async Task PostingModelInheritingType_HasRequiredAttributeValidationErrors() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<ModelInheritingTypeHavingRequiredAttributeValidationErrors" + " xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\"" + " xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<IsResidential>true</IsResidential><Zipcode>98052</Zipcode>" + "</ModelInheritingTypeHavingRequiredAttributeValidationErrors>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext( contentBytes, typeof(ModelInheritingTypeHavingRequiredAttributeValidationErrors)); // Act var model = await formatter.ReadAsync(context) as ModelInheritingTypeHavingRequiredAttributeValidationErrors; // Assert Assert.NotNull(model); Assert.Equal(98052, model.Zipcode); Assert.Equal(true, model.IsResidential); Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(Address).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName) }); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // Accept : application/xml //setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); // Content-Type: application/xml #region Register XML Input Formatter for new media type var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); #endregion #region Registering Input Formatter Media Links var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } #endregion #region Registering Custom Content Negotiation for Output Formatters => Accept : application/vnd.marvin.hateoas+json var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } #endregion }) // LOWERCASING => CamelCase .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); #region Register Repository Pattern services.AddScoped <ILibraryRepository, LibraryRepository>(); #endregion #region Property Mapping Service for Sorting Data services.AddTransient <IPropertyMappingService, PropertyMappingService>(); #endregion #region Shape Resources e.g. http://localhost:6058/api/authors?fields=id i.e. Dynamically Mapping AuthorDTO properties to Entity.Author for Data Shaping on the Controller Actions that do not support Dynamic Sorting services.AddTransient <ITypeHelperService, TypeHelperService>(); #endregion #region Generate URIs to previous and next page for PAGINATION // UrlHelper requires context in which the action (IActionHelper => GET / POST / DELETE / PUT / PATCH / .. etc) runs // Initiate first time its requested services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); // UrlHelper will generate URIs to an action (IActionHelper => GET / POST / DELETE / PUT / PATCH / .. etc) // .AddScoped is used so an instance is created once per request services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); #endregion #region HTTP Cache Header Middleware => Marvin.Cache.Headers => ETags in Response Headers are used services.AddHttpCacheHeaders( (expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); #endregion // microsoft.aspnetcore.responsecaching => Response caching relating services => ETags in Response Headers are used services.AddResponseCaching(); #region Rate Limiting and Throttling => How Many Requests per Minute/Hour/etc. // registering service services.AddMemoryCache(); // AspNetCoreRateLimit => 3rd part NuGet to configure limiting services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 10, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 2, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); #endregion }
public async Task PostingModel_WithDictionaryProperty_HasValidationErrorsOnKeyAndValue() { // Arrange var input = "<FavoriteLocations " + "i:nil=\"true\" xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\"" + " xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"/>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(FavoriteLocations)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.Null(model); Assert.Equal(2, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(Point).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName), string.Format(requiredErrorMessageFormat, nameof(Point.Y), typeof(Point).FullName) }); AssertModelStateErrorMessages( typeof(Address).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName) }); }
public async Task PostingModel_WithPropertyHavingNullableValueTypes_NoRequiredAttributeValidationErrors() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<ModelWithPropertyHavingTypeWithNullableProperties " + "xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\" " + "xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><CarInfoProperty>" + "<ServicedYears xmlns:a=\"http://schemas.datacontract.org/2004/07/System\"><a:int>2006</a:int>" + "<a:int>2007</a:int></ServicedYears><Year>2005</Year></CarInfoProperty>" + "</ModelWithPropertyHavingTypeWithNullableProperties>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext( contentBytes, typeof(ModelWithPropertyHavingTypeWithNullableProperties)); var expectedModel = new ModelWithPropertyHavingTypeWithNullableProperties() { CarInfoProperty = new CarInfo() { Year = 2005, ServicedYears = new List<int?>() } }; expectedModel.CarInfoProperty.ServicedYears.Add(2006); expectedModel.CarInfoProperty.ServicedYears.Add(2007); // Act var model = await formatter.ReadAsync(context) as ModelWithPropertyHavingTypeWithNullableProperties; // Assert Assert.NotNull(model); Assert.NotNull(model.CarInfoProperty); Assert.Equal(expectedModel.CarInfoProperty.Year, model.CarInfoProperty.Year); Assert.Equal(expectedModel.CarInfoProperty.ServicedYears, model.CarInfoProperty.ServicedYears); Assert.Empty(context.ActionContext.ModelState); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddDbContext <LibraryContext>(opt => opt.UseInMemoryDatabase("Library")); services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddMvc(opt => { opt.ReturnHttpNotAcceptable = true; opt.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); opt.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var jsonOutputFormatter = opt.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.hateoas+json"); jsonOutputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); jsonOutputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); services.AddResponseCaching(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddHttpCacheHeaders((expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); services.AddMemoryCache(); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
public async Task PostingListOfModels_WithRequiredAndDataMemberNoRequired_HasValidationErrors() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<ArrayOfProduct xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\"" + " xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Product><Id>" + "10</Id><Name>Phone</Name></Product></ArrayOfProduct>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(List<Product>)); // Act var model = await formatter.ReadAsync(context) as List<Product>; // Assert Assert.NotNull(model); Assert.Equal(1, model.Count); Assert.Equal(10, model[0].Id); Assert.Equal("Phone", model[0].Name); Assert.Equal(2, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(Product).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName) }); AssertModelStateErrorMessages( typeof(Address).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName) }); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.owpini.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.owpini.business.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.owpini.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); services.AddDbContext <OwpiniDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity <OwpiniUser, IdentityRole>() .AddEntityFrameworkStores <OwpiniDbContext>() .AddDefaultTokenProviders(); services.AddResponseCaching(); services.AddSwaggerGen(setupAction => { setupAction.SwaggerDoc("OwpiniApi", new Info { Title = "Owpini API Documentation" }); }); services.AddMemoryCache(); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddScoped <IOwpiniRepository, OwpiniRepository>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { // Return a 406 when an unsupported media type was requested options.ReturnHttpNotAcceptable = true; // Add XML formatters options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options)); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.ifeanyi.authorwithdateofdeath.full+xml"); options.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = options.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.ifeanyi.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.ifeanyi.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = options.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.ifeanyi.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // Caching middleware services.AddHttpCacheHeaders((expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); //services.AddResponseCaching(); services.AddMemoryCache(); //Rate limit middleware services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); services.AddResponseCaching(); var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddHttpCacheHeaders(exp => { exp.MaxAge = 30; }, vald => { vald.MustRevalidate = true; }); }
/// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services"></param> public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; // Add XML Output Formatter var xmlDataContractSerializerOutputFormatter = new XmlDataContractSerializerOutputFormatter(); xmlDataContractSerializerOutputFormatter.SupportedMediaTypes.Add("application/vnd.nagarro.hateoas+xml"); setupAction.OutputFormatters.Add(xmlDataContractSerializerOutputFormatter); // Add XML Input Formatter var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(setupAction); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.nagarro.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(setupAction)); // Custom JSON Output Formatters Media Types if (setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault() is JsonOutputFormatter jsonOutputFormatter) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.nagarro.hateoas+json"); } // Custom JSON Input Formatters Media Types if (setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault() is JsonInputFormatter jsonInputFormatter) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.nagarro.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.nagarro.authorwithdateofdeath.full+json"); } }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = this.Configuration.GetConnectionString("libraryDBConnectionString"); services.AddDbContextPool <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); services.AddCors(options => { options.AddPolicy(this.AllowSpecificOrigins, builder => builder.WithOrigins("http://localhost:4200")); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // Configure Caching services.AddHttpCachingMvc(); services.AddResponseCaching(); // Configure Memory Cache services.AddMemoryCache(); services.Configure <IpRateLimitOptions>(options => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule> { new RateLimitRule { Endpoint = "*", Limit = 1000, Period = "1m" }, new RateLimitRule { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => options.EnableEndpointRouting = false); //Microsoft.AspNetCore.Mvc.Formatters.Xml services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); //setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(setupAction)); }); services.AddMvc().AddNewtonsoftJson(); services.AddMvc().AddMvcOptions(options => { var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(options); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); options.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = options.InputFormatters .OfType <NewtonsoftJsonOutputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = options.OutputFormatters .OfType <NewtonsoftJsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.hateoas+json"); } }); // Microsoft.AspNetCore.Mvc.NewtonsoftJson services.AddControllers().AddNewtonsoftJson(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // HttpPatch services.AddControllersWithViews().AddNewtonsoftJson(); services.AddControllersWithViews(options => { options.InputFormatters.Insert(0, GetJsonPatchInputFormatter()); }); var config = new MapperConfiguration(cfg => { /*cfg.CreateMap<Author, AuthorDto>() * .ForMember(dest => dest.Name, opt => opt.MapFrom(src => * $"{src.FirstName} {src.LastName}")) * .ForMember(dest => dest.Age, opt => opt.MapFrom(src => * src.DateOfBirth.GetCurrentAge()));*/ cfg.CreateMap <Author, AuthorDto>() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}")) .ForMember(dest => dest.Age, opt => opt.MapFrom(src => src.DateOfBirth.GetCurrentAge(src.DateOfDeath))); cfg.CreateMap <Book, BookDto>(); cfg.CreateMap <AuthorForCreationDto, Author>(); cfg.CreateMap <AuthorForCreationWithDateOfDeathDto, Author>(); cfg.CreateMap <BookForCreationDto, Book>(); cfg.CreateMap <BookForUpdateDto, Book>(); cfg.CreateMap <Book, BookForUpdateDto>(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Startup.Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // Nuget Marvin.Cache.Headers services.AddHttpCacheHeaders( (expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.MustRevalidate = true; }); // Nuget AspNetCoreRateLimit services.AddMemoryCache(); /*services.Configure<IpRateLimitOptions>((options) => * { * options.GeneralRules = new System.Collections.Generic.List<RateLimitRule>() * { * new RateLimitRule() * { * Endpoint = "*", * Limit = 1000, * Period = "5m" * }*//*, * new RateLimitRule() * { * Endpoint = "*", * Limit = 200, * Period = "10s" * }*//* * }; * });*/ // needed to load configuration from appsettings.json services.AddOptions(); // needed to store rate limit counters and ip rules services.AddMemoryCache(); //load general configuration from appsettings.json services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); //load ip rules from appsettings.json services.Configure <IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies")); // inject counter and rules stores services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Add framework services. services.AddMvc(); // https://github.com/aspnet/Hosting/issues/793 // the IHttpContextAccessor service is not registered by default. // the clientId/clientIp resolvers use it. services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); // configuration (resolvers, counter key builders) services.AddSingleton <IRateLimitConfiguration, RateLimitConfiguration>(); IMapper mapper = config.CreateMapper(); services.AddSingleton(mapper); }
public async Task ReadAsync_ThrowsWhenNotConfiguredWithKnownTypes() { // Arrange var KnownTypeName = "SomeDummyClass"; var InstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; var input = string.Format( "<DummyClass i:type=\"{0}\" xmlns:i=\"{1}\"><SampleInt>1</SampleInt>" + "<SampleString>Some text</SampleString></DummyClass>", KnownTypeName, InstanceNamespace); var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act & Assert await Assert.ThrowsAsync(typeof(SerializationException), async () => await formatter.ReadAsync(context)); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { // If this is true then if the client's Accept header's value is not supported by the Outputformatters here then, // HttpStatus Response Code 406 will be sent back to the client setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } // **** We get hold of the FIRST JSON output formatter var jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); // and if it found then, we configure it to support custom media type shown below. // SO, as a result if the client sends an Http Request with an Accept: application/vnd.marvin.hateoas+json // the Output Formatter won't throw an error 406 Not Acceptable ..... // Then in our controller's Action's parameter we could do // [FromHeader(Name="Accept") string x] // and then compare x to "application/vnd.marvin.hateoas+json" or to "application/json" and place different // stuff in the Http Response body and Http Response Header depending on the API documentation .... if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // ***************** This will add directives to the Cache-Control Http Response Header ****************************** // There are many options and you will get intellisense when you do expirationModelOptions. or validationModelOptions. // ************************************ V IMP ******************************* // This will ALSO add the eTag, Last-Modified & Expires Http headers in addition to the directives in the // Cache-Control Header services.AddHttpCacheHeaders((expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); // ********************************************************************************************************************* // ***************** This service allows us to do DATA caching in the server's memory ********************************* // This is for DATA caching ... NOT NOT Http Response Caching ... // This is used by the IP Rate Limiting Middleware for storing API call counts in memory .... services.AddMemoryCache(); // ***************** This is configuring the https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/IpRateLimitMiddleware // MIDDLEWARE which controls how frequently the web apis can be called services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); // ************************************************************************************************************************ }
public async Task PostingListofModels_WithBothRequiredAndDataMemberRequired_NoValidationErrors() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<ArrayOfLaptop xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\"" + " xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Laptop><Id>" + "10</Id><SupportsVirtualization>true</SupportsVirtualization></Laptop></ArrayOfLaptop>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(List<Laptop>)); // Act var model = await formatter.ReadAsync(context) as List<Laptop>; // Assert Assert.NotNull(model); Assert.Equal(1, model.Count); Assert.Equal(10, model[0].Id); Assert.Equal(true, model[0].SupportsVirtualization); Assert.Empty(context.ActionContext.ModelState); }
public void ConfigureServices(IServiceCollection services) { //Added the connection string // services.AddDbContext<LibraryContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:LibraryContext"])); // services.AddDbContext<LibraryContext>(options => // options.UseSqlServer(Configuration.GetConnectionString("LibraryContext"))); services.AddDbContext <LibraryContext>(options => options.UseSqlServer("Server=RAHUL-PC;Database=Author_Api;Trusted_Connection=True;MultipleActiveResultSets=true;")); // services.AddDbContext<LibraryContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LibraryContext"))); services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // Auto Mapper Configurations var mappingConfig = new MapperConfiguration(mc => { mc.AddProfile(new MappingProfile()); }); IMapper mapper = mappingConfig.CreateMapper(); services.AddSingleton(mapper); // Set configuration to accept json or xml request type and return the response in the same type services.AddMvc(setUpAction => { //Default is false, which means this support all request type and return only in default type(json) // Setting true we can force that to return the response in the specified type(XML) setUpAction.ReturnHttpNotAcceptable = true; // Setting output formatter setUpAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // Setting input formatter //setUpAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); // configure xml input formatter var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.rahul.authorwithdateofdeath.full+xml"); setUpAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); // configure custom input header var jsonInputFormatter = setUpAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.rahul.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.rahul.authorwithdateofdeath.full+json"); } // configure custom output header var jsonOutputFormatter = setUpAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.rahul.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); // Disable automatic model state validation before comes into the controller services.Configure <ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; }); // Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(c => { // Add support for supporting multiple action with same path (api/CreateAuthor) c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); c.SwaggerDoc("v1", new Info { Title = "Author & Book service API", Version = "v1", Description = "This is dummy API application for author and book service. This project is based on the REST architecture.", Contact = new Contact { Name = "Rahul Sen", Email = "*****@*****.**" }, License = new License { Name = "Public - Mindfire", } }); // Set the comments path for the Swagger JSON and UI. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); }); // TODO:Update caching approach(https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-2.2) // Added http cache header middleware services.AddHttpCacheHeaders( (expirationModelOption) => { // Added different directices expirationModelOption.MaxAge = 600;; }, (validationModelOptions) => { validationModelOptions.MustRevalidate = true; }); // Add response caching related services services.AddResponseCaching(); // register service for adding support to limit the request and for this it required a memory cache to count the request services.AddMemoryCache(); // Limit for a particular ip address //services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new List <RateLimitRule>() { new RateLimitRule() { // full api endpoints Endpoint = "*", // limits 3 requests Limit = 10, // in 5 min time span can request resources for 10 times Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 2, Period = "10s" } }; }); // Register policy store and rate limit counter store services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IRateLimitConfiguration, RateLimitConfiguration>(); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); }
public async Task PostingModel_WithPropertySelfReferencingItself() { // Arrange var input = "<Employee xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\"" + " xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Id>10</Id><Manager><Id>11</Id><Manager" + " i:nil=\"true\"/><Name>Mike</Name></Manager><Name>John</Name></Employee>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(Employee)); var expectedModel = new Employee() { Id = 10, Name = "John", Manager = new Employee() { Id = 11, Name = "Mike" } }; // Act var model = await formatter.ReadAsync(context) as Employee; // Assert Assert.NotNull(model); Assert.Equal(expectedModel.Id, model.Id); Assert.Equal(expectedModel.Name, model.Name); Assert.NotNull(model.Manager); Assert.Equal(expectedModel.Manager.Id, model.Manager.Id); Assert.Equal(expectedModel.Manager.Name, model.Manager.Name); Assert.Null(model.Manager.Manager); Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(Employee).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Employee.Id), typeof(Employee).FullName) }); }
public async Task PostingModel_WithDifferentValueTypeProperties_HasValidationErrors() { // Arrange var input = "<ValueTypePropertiesModel i:nil=\"true\" " + "xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\" " + "xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"/>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(ValueTypePropertiesModel)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.Null(model); Assert.Equal(3, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(Point).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName), string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName) }); AssertModelStateErrorMessages( typeof(GpsCoordinate).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format( requiredErrorMessageFormat, nameof(GpsCoordinate.Latitude), typeof(GpsCoordinate).FullName), string.Format( requiredErrorMessageFormat, nameof(GpsCoordinate.Longitude), typeof(GpsCoordinate).FullName) }); AssertModelStateErrorMessages( typeof(ValueTypePropertiesModel).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format( requiredErrorMessageFormat, nameof(ValueTypePropertiesModel.IntProperty), typeof(ValueTypePropertiesModel).FullName), string.Format( requiredErrorMessageFormat, nameof(ValueTypePropertiesModel.DateTimeProperty), typeof(ValueTypePropertiesModel).FullName), string.Format( requiredErrorMessageFormat, nameof(ValueTypePropertiesModel.PointProperty), typeof(ValueTypePropertiesModel).FullName), string.Format( requiredErrorMessageFormat, nameof(ValueTypePropertiesModel.GpsCoordinateProperty), typeof(ValueTypePropertiesModel).FullName) }); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.arubesu.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.arubesu.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.arubesu.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.arubesu.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); //register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddHttpCacheHeaders( (ExpirationModelOptions) => { ExpirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.MustRevalidate = true; } ); services.AddResponseCaching(); // needed to load configuration from appsettings.json services.AddOptions(); // needed to store rate limit counters and ip rules services.AddMemoryCache(); //load general configuration from appsettings.json services.Configure <IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); // inject counter and rules stores services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Register the Swagger generator services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "Library API", Version = "v1" }); c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); }); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // ********************* // Setup CORS // ********************* var corsBuilder = new CorsPolicyBuilder(); corsBuilder.AllowAnyHeader(); corsBuilder.AllowAnyMethod(); corsBuilder.AllowAnyOrigin(); // For anyone access. //corsBuilder.WithOrigins("http://localhost:54816"); // for a specific url. Don't add a forward slash on the end! corsBuilder.AllowCredentials(); services.AddCors(options => { options.AddPolicy("SiteCorsPolicy", corsBuilder.Build()); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddResponseCaching(); services.AddHttpCacheHeaders( (expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); services.AddMemoryCache(); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSwaggerGen(setupAction => { setupAction.SwaggerDoc("libraryapi", new Swashbuckle.AspNetCore.Swagger.Info { Title = "Library API Documentation" }); }); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { // pokud je to false, tak nam vrati data v podporovanem formatu - JSON // pokud `nastavim ena true, tak nam to vyhodi 406 cybu pokud format nepodporujeme setupAction.ReturnHttpNotAcceptable = true; // nastavime ze pokud nekdo bude vyzadovat XML v headeru, tak mu ho posleme setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); // musime pridat vlastni MetaData type aby jsme ho mohli pouzivat // v Header Accept si normalne posleme jeho nazev a jen porovnavame se string/enum if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }).AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // pridame URLhealper k tomu abyu jsme mohli vytvaret previsous a next link services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddHttpCacheHeaders( (expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); services.AddMemoryCache(); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.NotNull(model); Assert.IsType<TestLevelOne>(model); var levelOneModel = model as TestLevelOne; Assert.Equal(expectedInt, levelOneModel.SampleInt); Assert.Equal(expectedString, levelOneModel.sampleString); }
public async Task ReadAsync_ReadsWhenMaxDepthIsModified() { // Arrange var expectedInt = 10; var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<DummyClass><SampleInt>" + expectedInt + "</SampleInt></DummyClass>"; var formatter = new XmlDataContractSerializerInputFormatter(); formatter.MaxDepth = 10; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<DummyClass>(result.Model); Assert.Equal(expectedInt, model.SampleInt); }
public void SetMaxDepth_ThrowsWhenMaxDepthIsBelowOne() { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); // Act & Assert Assert.Throws(typeof(ArgumentException), () => formatter.MaxDepth = 0); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>() .ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); // services.AddScoped<IUrlHelper, UrlHelper>(); }
public async Task ReadAsync_FallsbackToUTF8_WhenCharSet_NotInContentType() { // Arrange var expectedException = TestPlatformHelper.IsMono ? typeof(SerializationException) : typeof(XmlException); var expectedMessage = TestPlatformHelper.IsMono ? "Expected element 'TestLevelTwo' in namespace '', but found Element node 'DummyClass' in namespace ''" : "The expected encoding 'utf-8' does not match the actual encoding 'utf-16LE'."; var inpStart = Encoding.Unicode.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<DummyClass><SampleInt>"); byte[] inp = { 192, 193 }; var inpEnd = Encoding.Unicode.GetBytes("</SampleInt></DummyClass>"); var contentBytes = new byte[inpStart.Length + inp.Length + inpEnd.Length]; Buffer.BlockCopy(inpStart, 0, contentBytes, 0, inpStart.Length); Buffer.BlockCopy(inp, 0, contentBytes, inpStart.Length, inp.Length); Buffer.BlockCopy(inpEnd, 0, contentBytes, inpStart.Length + inp.Length, inpEnd.Length); var formatter = new XmlDataContractSerializerInputFormatter(); var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo)); // Act var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context)); Assert.Equal(expectedMessage, ex.Message); }
// Set up application services public void ConfigureServices(IServiceCollection services) { // Add MVC services to the services container services.AddControllers() .AddXmlDataContractSerializerFormatters() .AddXmlSerializerFormatters(); services.Configure <MvcOptions>(options => { // Since both XmlSerializer and DataContractSerializer based formatters // have supported media types of 'application/xml' and 'text/xml', it // would be difficult for a test to choose a particular formatter based on // request information (Ex: Accept header). // We'll configure the ones on MvcOptions to use a distinct set of content types. XmlSerializerInputFormatter xmlSerializerInputFormatter = null; XmlSerializerOutputFormatter xmlSerializerOutputFormatter = null; XmlDataContractSerializerInputFormatter dcsInputFormatter = null; XmlDataContractSerializerOutputFormatter dcsOutputFormatter = null; for (var i = options.InputFormatters.Count - 1; i >= 0; i--) { switch (options.InputFormatters[i]) { case XmlSerializerInputFormatter formatter: xmlSerializerInputFormatter = formatter; break; case XmlDataContractSerializerInputFormatter formatter: dcsInputFormatter = formatter; break; default: options.InputFormatters.RemoveAt(i); break; } } for (var i = options.OutputFormatters.Count - 1; i >= 0; i--) { switch (options.OutputFormatters[i]) { case XmlSerializerOutputFormatter formatter: xmlSerializerOutputFormatter = formatter; break; case XmlDataContractSerializerOutputFormatter formatter: dcsOutputFormatter = formatter; break; default: options.OutputFormatters.RemoveAt(i); break; } } xmlSerializerInputFormatter.SupportedMediaTypes.Clear(); xmlSerializerInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-xmlser")); xmlSerializerInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-xmlser")); xmlSerializerInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml")); xmlSerializerOutputFormatter.SupportedMediaTypes.Clear(); xmlSerializerOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-xmlser")); xmlSerializerOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-xmlser")); xmlSerializerOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml")); dcsInputFormatter.SupportedMediaTypes.Clear(); dcsInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-dcs")); dcsInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-dcs")); dcsInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml")); dcsOutputFormatter.SupportedMediaTypes.Clear(); dcsOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-dcs")); dcsOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-dcs")); dcsOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml")); options.InputFormatters.Add(dcsInputFormatter); options.InputFormatters.Add(xmlSerializerInputFormatter); options.OutputFormatters.Add(dcsOutputFormatter); options.OutputFormatters.Add(xmlSerializerOutputFormatter); xmlSerializerInputFormatter.WrapperProviderFactories.Add(new PersonWrapperProviderFactory()); xmlSerializerOutputFormatter.WrapperProviderFactories.Add(new PersonWrapperProviderFactory()); dcsInputFormatter.WrapperProviderFactories.Add(new PersonWrapperProviderFactory()); dcsOutputFormatter.WrapperProviderFactories.Add(new PersonWrapperProviderFactory()); }); }
public async Task ReadAsync_IgnoresBOMCharacters() { // Arrange var sampleString = "Test"; var sampleStringBytes = Encoding.UTF8.GetBytes(sampleString); var inputStart = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Environment.NewLine + "<TestLevelTwo><SampleString>" + sampleString); byte[] bom = { 0xef, 0xbb, 0xbf }; var inputEnd = Encoding.UTF8.GetBytes("</SampleString></TestLevelTwo>"); var expectedBytes = new byte[sampleString.Length + bom.Length]; var contentBytes = new byte[inputStart.Length + bom.Length + inputEnd.Length]; Buffer.BlockCopy(inputStart, 0, contentBytes, 0, inputStart.Length); Buffer.BlockCopy(bom, 0, contentBytes, inputStart.Length, bom.Length); Buffer.BlockCopy(inputEnd, 0, contentBytes, inputStart.Length + bom.Length, inputEnd.Length); var formatter = new XmlDataContractSerializerInputFormatter(); var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<TestLevelTwo>(result.Model); Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length); Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length); Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(model.SampleString)); }
public void HasProperSuppportedMediaTypes() { // Arrange & Act var formatter = new XmlDataContractSerializerInputFormatter(); // Assert Assert.True(formatter.SupportedMediaTypes .Select(content => content.ToString()) .Contains("application/xml")); Assert.True(formatter.SupportedMediaTypes .Select(content => content.ToString()) .Contains("text/xml")); }
public async Task ReadAsync_ThrowsWhenNotConfiguredWithRootName() { // Arrange var SubstituteRootName = "SomeOtherClass"; var SubstituteRootNamespace = "http://tempuri.org"; var input = string.Format( "<{0} xmlns=\"{1}\"><SampleInt xmlns=\"\">1</SampleInt></{0}>", SubstituteRootName, SubstituteRootNamespace); var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act & Assert await Assert.ThrowsAsync(typeof(SerializationException), async () => await formatter.ReadAsync(context)); }
public async Task ReadAsync_ReadsComplexTypes() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var expectedLevelTwoString = "102"; var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<TestLevelTwo><SampleString>" + expectedLevelTwoString + "</SampleString>" + "<TestOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestOne></TestLevelTwo>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<TestLevelTwo>(result.Model); Assert.Equal(expectedLevelTwoString, model.SampleString); Assert.Equal(expectedInt, model.TestOne.SampleInt); Assert.Equal(expectedString, model.TestOne.sampleString); }
public async Task PostingModel_WithDeeperHierarchy_HasValidationErrors() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<Store xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.AspNet.Mvc.Xml\"" + " xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" i:nil=\"true\" />"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(Store)); // Act var model = await formatter.ReadAsync(context) as Store; // Assert Assert.Null(model); Assert.Equal(3, context.ActionContext.ModelState.Keys.Count); AssertModelStateErrorMessages( typeof(Address).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName) }); AssertModelStateErrorMessages( typeof(Employee).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Employee.Id), typeof(Employee).FullName) }); AssertModelStateErrorMessages( typeof(Product).FullName, context.ActionContext, expectedErrorMessages: new[] { string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName) }); }
public async Task ReadAsync_ThrowsWhenReaderQuotasAreChanged() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<TestLevelTwo><SampleString>test</SampleString>" + "<TestOne><SampleInt>10</SampleInt>" + "<sampleString>test</sampleString></TestOne></TestLevelTwo>"; var formatter = new XmlDataContractSerializerInputFormatter(); formatter.XmlDictionaryReaderQuotas.MaxStringContentLength = 2; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo)); // Act & Assert await Assert.ThrowsAsync(typeof(SerializationException), async () => await formatter.ReadAsync(context)); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc( setupAction => { // ReturnHttpNotAcceptable forces consumer to specify a supported available data format // rather than defaulting to json when the consumer specifies an unsupported format such as xml. setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // Allow incoming requests (such as post) to use xml setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); // v2.1 - Support DoD posts using XML var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); // v2 - Date of death support with versioning via media types var jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } // Add support for custom media type of 'application/vnd.marvin.hateoas+json' using json var jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) .AddJsonOptions( options => { // Retain property name casing on serialization. options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); // register IUrlHelper to support returning pagination metadata from a controller services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); // Provides IUrlHelper with access to actions //services.AddScoped<IUrlHelper, UrlHelper>(); // Generates URIs for an action services.AddScoped <IUrlHelper, UrlHelper>( implementationFactory => { return(new UrlHelper(actionContext: implementationFactory.GetService <IActionContextAccessor>().ActionContext)); }); // Register custom IPropertyMappingService to support sorting services.AddTransient <IPropertyMappingService, PropertyMappingService>(); // Register custom service to support data shaping services.AddTransient <ITypeHelperService, TypeHelperService>(); // Add some support for caching with HTTP cache headers //services.AddHttpCacheHeaders(); // Can use this to configure the cache headers in the response for both the expiration and validation models services.AddHttpCacheHeaders( (expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (validationModelOptions) => { validationModelOptions.MustRevalidate = true; }); // Use MS .Net Core package for response caching. Seems to be the only option available. // Does not generate response headers (like marvin does) but it does handle them. // Before v2 there are some really nasty bugs so avoid v1! services.AddResponseCaching(); // Support for throttling... // Can throttle by IP and / or by client. // Can throttle by calls to specific controllers or methods // Can throttle by (for example); requests per day, requests per hour, and requests per controller. // Request headers for this are; X-Rate-Limit-Limit, X-Rate-Limit-Remaining, and X-Rate-Limit-Reset. // Disallowed requests will return a 429 response with an optional Retry-After header and a body explaining the condition. services.AddMemoryCache(); // Used to store throttling counters and rules // AspNetCoreRateLimit package contains two pieces of middleware for throttling by IP and by client. // Example for throttling by IP... // NB - Could also read this from the config file (not sure if a specific one should be used or just the appsettings.json) services.Configure <IpRateLimitOptions>( options => { options.GeneralRules = new List <RateLimitRule> { new RateLimitRule // 10 requests every 5 minutes { Endpoint = "*", //Limit = 10, Limit = 1000, Period = "5m" }, new RateLimitRule // 2 requests every 10 seconds { Endpoint = "*", //Limit = 2, Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
public async Task ReadAsync_VerifyStreamIsOpenAfterRead() { // Arrange var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<DummyClass><SampleInt>10</SampleInt></DummyClass>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); Assert.NotNull(result.Model); Assert.True(context.HttpContext.Request.Body.CanRead); }
public async Task ReadAsync_ReadsSimpleTypes() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.NotNull(model); Assert.IsType<TestLevelOne>(model); var levelOneModel = model as TestLevelOne; Assert.Equal(expectedInt, levelOneModel.SampleInt); Assert.Equal(expectedString, levelOneModel.sampleString); }
public async Task ReadAsync_UsesContentTypeCharSet_ToReadStream() { // Arrange var expectedException = TestPlatformHelper.IsMono ? typeof(SerializationException) : typeof(XmlException); var expectedMessage = TestPlatformHelper.IsMono ? "Expected element 'TestLevelTwo' in namespace '', but found Element node 'DummyClass' in namespace ''" : "The expected encoding 'utf-16LE' does not match the actual encoding 'utf-8'."; var inputBytes = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<DummyClass><SampleInt>1000</SampleInt></DummyClass>"); var formatter = new XmlDataContractSerializerInputFormatter(); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(inputBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, modelType: typeof(TestLevelOne)); // Act var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context)); Assert.Equal(expectedMessage, ex.Message); }
public async Task ReadAsync_ThrowsOnExceededMaxDepth() { if (TestPlatformHelper.IsMono) { // ReaderQuotas are not honored on Mono return; } // Arrange var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<TestLevelTwo><SampleString>test</SampleString>" + "<TestOne><SampleInt>10</SampleInt>" + "<sampleString>test</sampleString></TestOne></TestLevelTwo>"; var formatter = new XmlDataContractSerializerInputFormatter(); formatter.MaxDepth = 1; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo)); // Act & Assert await Assert.ThrowsAsync(typeof(SerializationException), async () => await formatter.ReadAsync(context)); }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.Unicode.GetBytes(input); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, modelType: typeof(TestLevelOne)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<TestLevelOne>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.sampleString); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(new MvcOptions())); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSerializerInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters .OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes .Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters .OfType <JsonOutputFormatter>().FirstOrDefault(); jsonOutputFormatter?.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); }).AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Version = "v1", Title = "Library RESTful API", Description = "Pluralsight Course: Building a RESTful API with ASP.NET Core", TermsOfService = "None", Contact = new Contact() { Name = "Justin Grimes", Email = "*****@*****.**", Url = "*****@*****.**" } }); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = _configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); // register action context accessor services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); // register url helper services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); // register property mapping service services.AddTransient <IPropertyMappingService, PropertyMappingService>(); // register type helper service services.AddTransient <ITypeHelperService, TypeHelperService>(); }
public async Task ReadAsync_ReadsWhenConfiguredWithRootName() { // Arrange var expectedInt = 10; var SubstituteRootName = "SomeOtherClass"; var SubstituteRootNamespace = "http://tempuri.org"; var input = string.Format( "<{0} xmlns=\"{1}\"><SampleInt xmlns=\"\">{2}</SampleInt></{0}>", SubstituteRootName, SubstituteRootNamespace, expectedInt); var dictionary = new XmlDictionary(); var settings = new DataContractSerializerSettings { RootName = dictionary.Add(SubstituteRootName), RootNamespace = dictionary.Add(SubstituteRootNamespace) }; var formatter = new XmlDataContractSerializerInputFormatter { SerializerSettings = settings }; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<DummyClass>(result.Model); Assert.Equal(expectedInt, model.SampleInt); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(opt => { opt.ReturnHttpNotAcceptable = true; opt.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); // opt.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(opt)); var xmlDataContractSerializerInputFormatter = new XmlDataContractSerializerInputFormatter(opt); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); xmlDataContractSerializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+xml"); opt.InputFormatters.Add(xmlDataContractSerializerInputFormatter); var jsonInputFormatter = opt.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); } var jsonOutputFormatter = opt.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath+json"); jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) .AddXmlDataContractSerializerFormatters() .AddJsonOptions(option => { option.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); services.AddCors(opt => { opt.AddPolicy("AllowOrigin", options => { options.AllowAnyOrigin(); options.AllowAnyHeader(); options.AllowAnyMethod(); }); }); var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); //generating prev and next routes services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); //Caching & concurrency services.AddHttpCacheHeaders(expirationOptions => { expirationOptions.MaxAge = 600; }, validationOptions => { validationOptions.MustRevalidate = true; }); //Caching & concurrency services.AddResponseCaching(); // Rate Limiting services.AddMemoryCache(); services.Configure <IpRateLimitOptions>(opt => { opt.GeneralRules = new List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IRateLimitConfiguration, RateLimitConfiguration>(); }
public async Task ReadAsync_ReadsWhenConfiguredWithKnownTypes() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var KnownTypeName = "SomeDummyClass"; var InstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; var input = string.Format( "<DummyClass i:type=\"{0}\" xmlns:i=\"{1}\"><SampleInt>{2}</SampleInt>" + "<SampleString>{3}</SampleString></DummyClass>", KnownTypeName, InstanceNamespace, expectedInt, expectedString); var settings = new DataContractSerializerSettings { KnownTypes = new[] { typeof(SomeDummyClass) } }; var formatter = new XmlDataContractSerializerInputFormatter { SerializerSettings = settings }; var contentBytes = Encoding.UTF8.GetBytes(input); var context = GetInputFormatterContext(contentBytes, typeof(DummyClass)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<SomeDummyClass>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.SampleString); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc( setup => { setup.ReturnHttpNotAcceptable = true; setup.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); var xmlInputFormatter = new XmlDataContractSerializerInputFormatter(new MvcOptions { }); xmlInputFormatter.SupportedMediaTypes.Add(VendorMediaType.NewAuthorDeadXml); setup.InputFormatters.Add(xmlInputFormatter); var jsonOutputFormatter = setup.OutputFormatters.OfType <NewtonsoftJsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add(VendorMediaType.HateoasLinks); } var jsonInputFormatter = setup.InputFormatters.OfType <NewtonsoftJsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add(VendorMediaType.NewAuthor); jsonInputFormatter.SupportedMediaTypes.Add(VendorMediaType.NewAuthorDead); } //setup.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); } ).AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver() ) .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); services.AddControllersWithViews(options => { options.InputFormatters.Insert(0, GetJsonPatchInputFormatter()); }); var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>(imp => { var actionContext = imp.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); } ); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddHttpCacheHeaders( options => { options.MaxAge = 600; }, validationOptions => { validationOptions.AddMustRevalidate = true; } ); services.AddResponseCaching(); services.AddMemoryCache(); services.AddSingleton <IProcessingStrategy, AsyncKeyLockProcessingStrategy>(); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IRateLimitConfiguration, RateLimitConfiguration>(); services.AddMemoryCache(); services.AddSingleton <IClientPolicyStore, MemoryCacheClientPolicyStore>(); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule { Endpoint = "*", Limit = 1000, Period = "5m" //PeriodTimespan = new TimeSpan(0,5,0) }, new RateLimitRule { Endpoint = "*", Limit = 200, Period = "10s" //PeriodTimespan = new TimeSpan(0,0,10) } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); //setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); var xmlDataContractSarializerInputFormatter = new XmlDataContractSerializerInputFormatter(); xmlDataContractSarializerInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSarializerInputFormatter); var jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.alienonwork.hateoas+json"); } }) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddHttpCacheHeaders( (expirationModelOptions) => expirationModelOptions.MaxAge = 600, (validationModelOptions) => { validationModelOptions.AddMustRevalidate = true; }); services.AddResponseCaching(); services.AddMemoryCache(); services.Configure <IpRateLimitOptions>((options) => { options.GeneralRules = new System.Collections.Generic.List <RateLimitRule>() { new RateLimitRule() { Endpoint = "*", Limit = 1000, Period = "5m" }, new RateLimitRule() { Endpoint = "*", Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(setupAction => { setupAction.ReturnHttpNotAcceptable = true; // default outputformatter: the first one in this list // it will be used if no accept-header was specified setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); //setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(new MvcOptions())); var xmlDataContractSerializer = new XmlDataContractSerializerInputFormatter(new MvcOptions()); xmlDataContractSerializer.SupportedMediaTypes.Add("application/vnd.marvin.authorwithdateofdeath.full+xml"); setupAction.InputFormatters.Add(xmlDataContractSerializer); var jsonInputFormatter = setupAction.InputFormatters.OfType <JsonInputFormatter>().FirstOrDefault(); if (jsonInputFormatter != null) { jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.author.full+json"); jsonInputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.authorwithtimeofdeath.full+json"); } var jsonOutputFormatter = setupAction.OutputFormatters.OfType <JsonOutputFormatter>().FirstOrDefault(); if (jsonOutputFormatter != null) { jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }) // the default contract resolver serializes the data "as-is", and now we use ExpandoObject for data repr. // before the serialization, whose dictionary'keys are not camel case. .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); // register the DbContext on the container, getting the connection string from // appSettings (note: use this during development; in a production environment, // it's better to store the connection string in an environment variable) var connectionString = Configuration["connectionStrings:libraryDBConnectionString"]; services.AddDbContext <LibraryContext>(o => o.UseSqlServer(connectionString)); // register the repository services.AddScoped <ILibraryRepository, LibraryRepository>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper, UrlHelper>(implementationFactory => { var actionContext = implementationFactory.GetService <IActionContextAccessor>().ActionContext; return(new UrlHelper(actionContext)); }); // lightweight, stateless ->transient services.AddTransient <IPropertyMappingService, PropertyMappingService>(); services.AddTransient <ITypeHelperService, TypeHelperService>(); services.AddHttpCacheHeaders( (ExpirationModelOptions expirationModelOptions) => { expirationModelOptions.MaxAge = 600; }, (ValidationModelOptions validationModelOptions) => { validationModelOptions.MustRevalidate = true; }); services.AddResponseCaching(); services.AddMemoryCache(); services.Configure <IpRateLimitOptions>(options => { options.GeneralRules = new List <RateLimitRule> { new RateLimitRule { Endpoint = "*", //Limit = 10, Limit = 1000, Period = "5m" }, new RateLimitRule { Endpoint = "*", //Limit = 2, Limit = 200, Period = "10s" } }; }); services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>(); }