I'm switching to System.Text.Json from Json.Net, and the following is no longer serializable:
Microsoft.AspNetCore.Http.FormFile
The exception is:
System.NotSupportedException : The collection type 'Microsoft.AspNetCore.Http.IHeaderDictionary' on 'Microsoft.AspNetCore.Http.FormFile.Headers' is not supported.`
Will this be supported? Are there any workarounds?
Are there any workarounds?
Are you able to implement a custom JsonConverter?
@scalablecory Maybe... I was worried I'd be opening a can of worms and writing 20 converters for something Json.Net already supported.
@joshmouch out of curiosity, why are you serializing a FormFile? what is the output of newtonsoft serializing it?
When I expose an Iformfile then generate a swagger client from it, the generated client excepts a Stream type. I have to include a custom type filter for Swashbuckler, though.
cc @pranavkm, @rynowak
@joshmouch - just curious.. what do you expect to happen with JSON serialization and IFormFile - I would be really surprised if it did anything useful.
@rynowak
In Asp.net Core 2.2 with JSON.Net, you can upload a file to an API operation with an auto-generated swagger definition and a strongly-typed auto generated client.
Use AutoRest.exe to generate a client from the Swagger.json definition. This client will have methods that can send files to the API via System.IO.Stream objects.
That's pretty cool! I didn't realize that Autorest could do that.
Do you have the full callstack of that exception? What part of the code is blowing up. I'm asking because I want to see if we can find a workaround to unblock you.
Sure thing!
System.NotSupportedException : The collection type 'Microsoft.AspNetCore.Http.IHeaderDictionary' on 'Microsoft.AspNetCore.Http.FormFile.Headers' is not supported.
at System.Text.Json.JsonClassInfo.GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo.CreateProperty(Type declaredPropertyType, Type runtimePropertyType, Type implementedPropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonConverter converter, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo.AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo..ctor(Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializerOptions.GetOrAddClass(Type classType)
at System.Text.Json.WriteStackFrame.Initialize(Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|21_0(ResourceInvoker invoker, IActionResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
...
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
at IdentityServer4.Hosting.MutualTlsTokenEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
...
at Microsoft.AspNetCore.TestHost.HttpContextBuilder.<>c__DisplayClass20_0.<<SendAsync>g__RunRequestAsync|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.TestHost.ClientHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
...
This callstack implies to me that this API returns an IFileInfo - is that the case?
@rynowak ,
You are correct. I had this mixed up. So it's when an IFormFile is returned from an API operation that it's bombing, not when an operation is accepting one. Let me gather some more information and respond on this thread.
I had the same problem serializing Request.Headers (Microsoft.AspNetCore.Http.IHeaderDictionary). Luckily an extension method exists:
var d = Request.Headers.ToDictionary(k=>k.Key, v=>v.Value);
I have the same issue. Is there already a solution for this?
The same error.
I don't have this issue anymore. The problem was caused by what I RETURNED from the Controller method instead of the parameter of the method.
For the input of the method I want to have the uploaded file IFormFile type, but also the meta data. So what I did was create a base class (CustomFile) with attributes like name and such. Then I created a subclass (UploadFile) that inherits from CustomFile and adds the IFormFile as a field.
As the standard method to implement this is the POST method, the standard return is CreatedAtAction("GetCustomFile", ...). What I did here before was return the UploadFile - and this causes the error. But I don't want to return the file to the client, but just the meta data (CustomFile). When I changed that, error was gone.
Does this help for you? I hope I explained it in a way you can understand it :)
Hi,
Is there any solution for this issue. I have .Net core app developed with 2.2 and Just update it with 3.1 and it breaks the working code. Following is the stack trace of error. Please suggest if any solution for this.
System.NotSupportedException: The collection type 'Microsoft.AspNetCore.Http.IHeaderDictionary' on 'Microsoft.AspNetCore.Http.IFormFile.Headers' is not supported.
at System.Text.Json.JsonClassInfo.GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo.CreateProperty(Type declaredPropertyType, Type runtimePropertyType, Type implementedPropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonConverter converter, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo.AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo..ctor(Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializerOptions.GetOrAddClass(Type classType)
at System.Text.Json.JsonPropertyInfo.get_ElementClassInfo()
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Infrastructure.SystemTextJsonResultExecutor.ExecuteAsync(ActionContext context, JsonResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.SystemTextJsonResultExecutor.ExecuteAsync(ActionContext context, JsonResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNextTFilter,TFilterAsync
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at ElmahCore.Mvc.ErrorLogMiddleware.Invoke(HttpContext context, Func`1 next)
at ElmahCore.Mvc.BuilderHelper.<>c.<
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
@jigneshpclarion are you returning an IFormFile in your API method? That's not the way to return a file and might cause this issue.
@mtirion - I'm not returning IFromfil in API method. Below is the API method code.
[HttpGet("{id}")]
public async Task<IActionResult> GetItem(int id)
{
var item = await itemService.Get(id);
if (item == null)
{
return NotFound();
}
return new JsonResult(item);
}
@jigneshpclarion what's the definition of the item? And are you sure it's failing on this method? Your stacktrace shows that there is an issue with the Microsoft.AspNetCore.Http.IFormFile.Headers.
Before upgrading to .net core 3.1 following response returned by this method.
{
"data": {
"itemId": 16,
"elite": true,
"curatorsPick": true,
"isActive": true,
"itemCompleted": false,
"isLock": true,
"readyForWebSite": true,
"previous": 0,
"next": 0,
"isTiffOnServer": null,
"tiffNotes": null,
"name": "KAUSHIK 1234",
"itemSubject": "16Subject",
"itemCreateDateDay": 1,
"itemCreateDateMonth": 2,
"itemCreateDateYear": 2001,
"isApproximateDate": false,
"itemCreateDateText": "Summer ",
"itemFromName": 346,
"itemFromState": null,
"itemFromCountry": 57,
"itemFromCity": 335,
"itemFromAddress": "32685 SBL",
"itemFromGPSLatitude": null,
"itemFromGPSLongitude": null,
"itemToFirstName": "_round",
"itemToLastName": "_andaround",
"itemToState": 195,
"itemToCountry": 256,
"itemToCity": null,
"itemToAddress": null,
"itemToGPSLatitude": null,
"itemToGPSLongitude": null,
"itemTypeId": 7,
"pagesNum": 7,
"sizeId": 1,
"itemWidth": 9,
"itemHeight": 9,
"itemWidthInch": 9,
"itemHeightInch": 9,
"itemImages": [
{
"itemPageId": 271,
"itemId": 16,
"pageWidth": 190,
"pageHeight": 150,
"pageNumber": 1,
"comment": null,
"pageUrl": "http://server.blob.core.windows.net/collectioncollection/Scan%5C637019849346478557_58_thumb.jpg",
"pageName": "58_thumb.jpg",
"pageTranscript": null,
"pageTransLowResImageFilename": null
},
{
"itemPageId": 272,
"itemId": 16,
"pageWidth": 1200,
"pageHeight": 962,
"pageNumber": 2,
"comment": null,
"pageUrl": "http://server.blob.core.windows.net/collection/Scan%5C637019849399027141_59_New.jpg",
"pageName": "59_New.jpg",
"pageTranscript": null,
"pageTransLowResImageFilename": null
},
{
"itemPageId": 273,
"itemId": 16,
"pageWidth": 254,
"pageHeight": 150,
"pageNumber": 3,
"comment": null,
"pageUrl": "http://server.blob.core.windows.net/collection/Scan%5C637019849424977408_88_thumb.jpg",
"pageName": "88_thumb.jpg",
"pageTranscript": null,
"pageTransLowResImageFilename": null
},
{
"itemPageId": 290,
"itemId": 16,
"pageWidth": 290,
"pageHeight": 410,
"pageNumber": 4,
"comment": null,
"pageUrl": "http://server.blob.core.windows.net/collection/Scan%5C637129899206841546_nerdy_giraffe.jpg",
"pageName": "nerdy_giraffe.jpg",
"pageTranscript": "<p>Nerdy by Nature</p>\n",
"pageTransLowResImageFilename": null
}
],
"itemContent": "<p><strong>FOR TESTING PURPOSE </strong></p>",
"itemPhysicalDescription": "<p></p>\n",
"categoryId": 39,
"subCategoryId": 201,
"theme": [
{
"name": "ARC- Architecture",
"itemThemeId": 84,
"themeId": 39
},
{
"name": "JP - Jewish Personalities",
"itemThemeId": 85,
"themeId": 10
}
],
"tag": [],
"itemNote": [],
"itemDocument": [],
"journey": [
{
"name": "abc1234",
"journeyId": 30,
"itemJourneyId": 33,
"url": "https:///1233.com"
},
{
"name": "Great White Jail1",
"journeyId": 6,
"itemJourneyId": 34,
"url": "http://uii.com"
},
{
"name": "Herzl",
"journeyId": 9,
"itemJourneyId": 42,
"url": "https://Herzl"
},
{
"name": "Ya Basic! The Good Place <3",
"journeyId": 23,
"itemJourneyId": 43,
"url": "https://youtu.be/fpFWPze_nIs"
}
],
"collection": [],
"itemBetweenTheLine": [],
"biography": [],
"itemCost": null,
"insuranceValue": null,
"insuranceValueDate": "2019-05-15T13:00:00",
"locationId": 21,
"locationViewDate": "2019-05-14T18:30:00",
"referenceNumber": null,
"futureHandlingId": null,
"dealerId": 62,
"dealerCatalog": null,
"dealerDate": "2019-05-14T18:30:00",
"dealerLotNumber": null,
"platformId": null,
"itemRemarks": "<p>ssssssssssss test11696</p>\n",
"itemStatusId": 2,
"userId": 6,
"shortTitle": "Richard",
"previewText": "test preview text12",
"websiteFilter": [
13,
15
],
"marketingTag": [],
"relatedItems": [],
"relatedManus": [],
"itemMetaTitle": "test",
"itemMetaDescription": "test description",
"itemFriendlyUrl": "https://www.youtube.com/watch?v=2F36ENlOggY&list=RD2F36ENlOggY&start_radio=1",
"optimizedPageText": null,
"optimizedPageTextDate": null,
"optimizedPageTextUser": null,
"optimizedPageTextUserName": "",
"optimizedInternalLink": 3,
"optimizedInternalLinkDate": "2019-11-22T18:00:16.9",
"optimizedInternalLinkUser": 6,
"optimizedInternalLinkUserName": "string",
"seoStatus": 1,
"seoStatusDate": "2019-08-30T11:06:00.873",
"seoStatusUser": 6,
"seoStatusUserName": "string",
"marketingNotes": null,
"previewWebsiteImageUrl": null,
"wiki": null,
"seo": null,
"xcif": null,
"country": null,
"state": null,
"city": null,
"loggedInUser": 0,
"category": "Architecture1",
"subCategory": "Best Subcategory Eva!"
},
"message": null,
"exception": null,
"error": false,
"result": 0,
"extraData": null
}
What happens when you do a JsonConvert in the method itself and return that as a string? Will that solve your problem?
This following code fails for me even when it's empty
```c#
class Test
{
public IList
}
...
var str = JsonSerializer.Serialize(new Test());
System.NotSupportedException: The collection type 'Microsoft.AspNetCore.Http.IHeaderDictionary' on 'Microsoft.AspNetCore.Http.IFormFile.Headers' is not supported.
at System.Text.Json.JsonClassInfo.GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo.CreateProperty(Type declaredPropertyType, Type runtimePropertyType, Type implementedPropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonConverter converter, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo.AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options)
at System.Text.Json.JsonClassInfo..ctor(Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializerOptions.GetOrAddClass(Type classType)
at System.Text.Json.JsonPropertyInfo.get_ElementClassInfo()
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteCore(Utf8JsonWriter writer, Object value, Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializer.WriteCore(PooledByteBufferWriter output, Object value, Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializer.WriteCoreString(Object value, Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializer.SerializeTValue
```
I don't have this issue anymore. The problem was caused by what I RETURNED from the Controller method instead of the parameter of the method.
For the input of the method I want to have the uploaded file IFormFile type, but also the meta data. So what I did was create a base class (CustomFile) with attributes like name and such. Then I created a subclass (UploadFile) that inherits from CustomFile and adds the IFormFile as a field.
As the standard method to implement this is the POST method, the standard return is CreatedAtAction("GetCustomFile", ...). What I did here before was return the UploadFile - and this causes the error. But I don't want to return the file to the client, but just the meta data (CustomFile). When I changed that, error was gone.
Does this help for you? I hope I explained it in a way you can understand it :)
This works for me. Basically the FileInfo that consists of the upload file should NOT be returned to the CreatedAtAction method.
I don't have this issue anymore. The problem was caused by what I RETURNED from the Controller method instead of the parameter of the method.
For the input of the method I want to have the uploaded file IFormFile type, but also the meta data. So what I did was create a base class (CustomFile) with attributes like name and such. Then I created a subclass (UploadFile) that inherits from CustomFile and adds the IFormFile as a field.
As the standard method to implement this is the POST method, the standard return is CreatedAtAction("GetCustomFile", ...). What I did here before was return the UploadFile - and this causes the error. But I don't want to return the file to the client, but just the meta data (CustomFile). When I changed that, error was gone.
Does this help for you? I hope I explained it in a way you can understand it :)
thanks, it helped me.
i was trying to upload file using IFormFile as paramter, process it and at the end send back to client.
during this process, the file uploaded successfully but response was coming with status code 500.
Visual studio thrown that "could not open file '...undefined'
After reading you comment, i just removed the file from response and gave a message in string and it return 200 status code.
may this help someone else too.
thanks again
The issue here is that the element type StringValues is currently not supported for deserialization as it doesn't have a public parameterless ctor. Serialization of this type is supported.
The serializer would need to implement a new convention where we check for ctors that take a T array (T[]). Moving to future as a custom converter can be written to handle this.
The best way to resolve this while retrieving [Get] is to use the [JsonIgnore] attribute,
class FileModel
{
[JsonIgnore]
public List<IFormFile> file { get; set; }
}
Most helpful comment
I don't have this issue anymore. The problem was caused by what I RETURNED from the Controller method instead of the parameter of the method.
For the input of the method I want to have the uploaded file IFormFile type, but also the meta data. So what I did was create a base class (CustomFile) with attributes like name and such. Then I created a subclass (UploadFile) that inherits from CustomFile and adds the IFormFile as a field.
As the standard method to implement this is the POST method, the standard return is CreatedAtAction("GetCustomFile", ...). What I did here before was return the UploadFile - and this causes the error. But I don't want to return the file to the client, but just the meta data (CustomFile). When I changed that, error was gone.
Does this help for you? I hope I explained it in a way you can understand it :)