4

I get this really informative error. But cannot find the issue.

{"ClassName":"Newtonsoft.Json.JsonSerializationException","Message":"Could not create an instance of type Microsoft.AspNetCore.Http.IFormFile. Type is an interface or abstract class and cannot be instantiated. Path 'file.ContentDisposition', line 1, position 63.","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":"   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)\r\n   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)\r\n   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)\r\n   at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)\r\n   at Microsoft.Azure.Cosmos.CosmosJsonDotNetSerializer.FromStream[T](Stream stream)\r\n   at Microsoft.Azure.Cosmos.CosmosJsonSerializerWrapper.FromStream[T](Stream stream)\r\n   at Microsoft.Azure.Cosmos.CosmosSerializerCore.FromStream[T](Stream stream)\r\n   at Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.ToObjectpublic[T](ResponseMessage responseMessage)\r\n   at Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.<CreateItemResponse>b__8_0[T](ResponseMessage cosmosResponseMessage)\r\n   at Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.ProcessMessage[T](ResponseMessage responseMessage, Func`2 createResponse)\r\n   at Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.CreateItemResponse[T](ResponseMessage responseMessage)\r\n   at Microsoft.Azure.Cosmos.ContainerCore.CreateItemAsync[T](CosmosDiagnosticsContext diagnosticsContext, T item, Nullable`1 partitionKey, ItemRequestOptions requestOptions, CancellationToken cancellationToken)\r\n   at Microsoft.Azure.Cosmos.ClientContextCore.RunWithDiagnosticsHelperAsync[TResult](CosmosDiagnosticsContext diagnosticsContext, Func`2 task)\r\n   at SmartLearning_salon.Services.Person.PersonService.AddItemAsync(Person person) in C:\\Users\\knoer\\source\\repos\\SmartLearning_salon\\SmartLearning_salon\\Services\\Person\\PersonService.cs:line 25\r\n   at SmartLearning_salon.Controllers.PersonController.Create(Person person) in C:\\Users\\knoer\\source\\repos\\SmartLearning_salon\\SmartLearning_salon\\Controllers\\PersonController.cs:line 67","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":null,"HResult":-2146233088,"Source":"Newtonsoft.Json","WatsonBuckets":null}

The controller in my ASP.NET MVC app first sends a file to Azure Storage and then add a record to Cosmos DB. Both file and the record are saved/stored correctly. But then after save the page returns with the following error "Could not create an instance of type Microsoft.AspNetCore.Http.IFormFile"

I know that it is not possible to instantiate an object from an interface, but where is this happening?

In my ASP.NET MVC Core 3.1 I have a model that looks like this

public class Person
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }

    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "ssn")]
    public string Ssn { get; set; }

    //[JsonProperty(PropertyName = "testresult")]
    //public bool TestResult { get; set; }

    [JsonProperty(PropertyName = "file")]
    public IFormFile File { get; set; }

}

My PersonController looks like this

        // POST: PersonController/Create
        [HttpPost]
        [ValidateAntiForgeryToken]
        public  async Task<ActionResult> Create(Person person)
        {
            using (var stream = new MemoryStream())
            {
                try
                {
                    // assume a single file POST
                    await person.File.CopyToAsync(stream);
                    stream.Seek(0, SeekOrigin.Begin);

                    // now send blob up to Azure
                    await _blobStorageService.CreateBlobAsync(person.File.OpenReadStream(), person.File.FileName);

                    // send to Cosmos
                    await _personService.AddItemAsync(person);

                    //Ændre dette til at returnere et til detail view
                    return View("Person");
                    //return Ok(new { fileuploaded = true });
                }
                catch (Exception ex)
                {
                    return BadRequest(ex);
                }
            }

        }

My PersonService

        public async Task AddItemAsync(Models.Person person)
        {
            await container.CreateItemAsync(person, new PartitionKey(person.Id));
        }

My StorageService

  public async Task CreateBlobAsync(Stream stream, string filename)
        {
            try
            {
                //Opret hvis ikkke eksisterer
                await bcc.CreateIfNotExistsAsync();

                await bcc.UploadBlobAsync(filename, stream);
            }
            catch (Exception)
            {

                throw;
            }

        }

I really appriciate all the help that I can get.

Thanks Klaus

1 Answer 1

1

IFormFile is an interface. They can't be created without context.

You are trying to use your form-encoded version of Person to model data storage.

You should have two separate models: one for your form submission, the other for your data storage:

public class PersonForm
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Ssn { get; set; }
    public IFormFile File { get; set; }
}

public class Person
{
    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("ssn")]
    public string Ssn { get; set; }

    [JsonProperty("fileName")]
    public string FileName { get; set; }
}

Then your endpoint would look like this:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([FromForm] PersonForm personForm)
{
    try
    {
        // now send blob up to Azure
        await _blobStorageService.CreateBlobAsync(
            personForm.File.OpenReadStream(), personForm.File.FileName);

        // send to Cosmos
        await _personService.AddItemAsync(new Person
        {
            Id = personForm.Id,
            Name = personForm.Name,
            Ssn = personForm.Ssn,
            FileName = personForm.File.FileName
        });

        //Ændre dette til at returnere et til detail view
        return View("Person");
    }
    catch (Exception ex)
    {
        return BadRequest(ex);
    }
}

You could make use of AutoMapper to make it much easier to copy over DTO objects when a lot of the properties are the same.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks very much for you feedback. A follow up question. I also would like to persist IFormFile data about the stored image on the Cosmos database. Is that posible?
@KN -- no. IFormFile is strictly made to transfer files from the frontend to the backend. You can't persist those. They live for the lifetime of the request then they disappear. But, you could put a reference to the name that ended up in blob storage. Updated my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.