I've written some code (MetadataProcessor) that locates an xml file and sends it to an API ( http://localhost:5000/api/Events/UploadAzureEncodedMetadata ) to be parsed. However, when the API is called, the IFormFile parameter is always null. I've examined the resulting http request with fiddler to determine what is causing the model-binding problem (if that's what it is), but I see nothing wrong.
Metadata processor:
// Build a path to the directory containing the metadata file
string folderName = string.Format("OUTPUT_ENCODER_{0}_{1}", eventId, id);
string folderPath = Path.Combine(
this._config.MediaBasePath,
clientId.ToString(),
eventId.ToString(),
"results",
folderName);
// Find the metadata file
string fileName = null;
byte[] data = null;
bool exists = false;
string[] files = Directory.GetFiles(folderPath);
foreach (var file in files)
{
if (file.EndsWith("_metadata.xml"))
{
data = File.ReadAllBytes(file);
exists = true;
fileName = file;
break;
}
}
// Generate token for access to Events controller
TokenProvider tokens = new TokenProvider(this._config, this._logger);
var authValue = new AuthenticationHeaderValue("Bearer", tokens.GetTokenObject(clientId));
// Build the HttpClient
HttpClient client = new HttpClient()
{
DefaultRequestHeaders =
{
Authorization = authValue
}
};
// Bundle the xml data into the request body
ByteArrayContent formFile = new ByteArrayContent(data, 0, data.Length);
MultipartFormDataContent multiContent = new MultipartFormDataContent();
multiContent.Add(formFile, "formFile", fileName);
// Post to EventsController
var baseUri = new Uri(this._config.BaseUrl);
var url = new Uri(baseUri, string.Format("{0}api/Events/UploadAzureEncodedMetadata/{1}", baseUri, videoId));
var result = await client.PostAsync(url.ToString(), multiContent);
The MVC controller in the API:
[HttpPost("UploadAzureEncodedMetadata/{id}")]
[ProducesResponseType(201)]
[ProducesResponseType(400)]
[ProducesResponseType(401)]
[ProducesResponseType(404)]
public async Task<IActionResult> UpdateDuration([FromRoute]Guid id, [FromForm]IFormFile formFile)
{
// Find the video to update
var video = await this.context.Videos.Where(v => v.Id == id).SingleOrDefaultAsync();
if(formFile == null)
{
return this.BadRequest();
}
// Ensure that the service account has authorization
var eventId = video.EventId;
if (!await this.securityProvider.HasEventEditAccessAsync(eventId))
{
return this.Unauthorized();
}
// Attempt to deserialize the xml
int videoDuration = 0;
try
{
var serializer = new XmlSerializer(typeof(AssetFiles));
Stream stream = formFile.OpenReadStream();
var assetFiles = (AssetFiles)serializer.Deserialize(stream);
// Find duration and convert to seconds
string durationString = assetFiles.AssetFile.Duration;
TimeSpan durationTimeSpan = XmlConvert.ToTimeSpan(durationString);
videoDuration = (int)durationTimeSpan.TotalSeconds;
}
catch(Exception ex)
{
return this.BadRequest();
}
// Update the video entry
video.Duration = videoDuration;
await this.context.SaveChangesAsync();
return this.NoContent();
}
Lastly, here's a raw readout of the http request produced by the MetadataProcessor, that resulted in a null value for formFile in the controller:
POST http://localhost:5000/api/Events/UploadAzureEncodedMetadata/dc14829c-3d1b-4379-615b-08d5f8d07e16 HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1OWNiODg5YS01YjRjLTRlMzUtOWMyOS0zYWQ3MGU4NTJhYTgiLCJqdGkiOiI5OTU3MWIyMy0xYTQwLTQ0OTUtOTE2Zi03NDY5YjYwYzI1N2MiLCJpYXQiOjE1MzM4MzM4NzAsIkV2ZW50UmVnVXNlciI6ZmFsc2UspOgHjFVudElkIjoiMTdhMjc4NDYtOTc1My00OGEzLTRlYzEtMDhkNGUxMjgwZjVhIiwibmJmIjoxNTMzODMzODcwLCJleHAiOjE1MzM4MzM5MzAsImlzcyI6IjYzYmVmM2NkYTM1OTRmZjBhOTdiYWFiYWJjYTQzODhmIiwiYXVkIjoiSW5mZXJub0NvcmUifQ.rhIjYRUtFjHWrrgd9XnmW4kMXaZ5UFyr2ApNK1EBJRI
Content-Type: multipart/form-data; boundary="1b6c2d6e-53d6-414c-bb1b-681ff9c766f0"
Content-Length: 2951
Host: localhost:5000
--1b6c2d6e-53d6-414c-bb1b-681ff9c766f0
Content-Disposition: form-data; name=formFile; filename="C:\tmp\17a27846-9753-48a3-4ec1-08d4e1280f5a\213e65ee-fff9-4668-b123-7d0746bb4b05\results\OUTPUT_ENCODER_213e65ee-fff9-4668-b123-7d0746bb4b05_00000000-0000-0000-0000-000000000000\a35f0612-7a07-4bec-a9fd-a61d2a2f71bb_metadata.xml"; filename*=utf-8''C%3A%5Ctmp%5C17a27846-9753-48a3-4ec1-08d4e1280f5a%5C213e65ee-fff9-4668-b123-7d0746bb4b05%5Cresults%5COUTPUT_ENCODER_213e65ee-fff9-4668-b123-7d0746bb4b05_00000000-0000-0000-0000-000000000000%5Ca35f0612-7a07-4bec-a9fd-a61d2a2f71bb_metadata.xml
<?xml version="1.0" encoding="utf-8"?>
<AssetFiles xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/windowsazure/mediaservices/2014/07/mediaencoder/inputmetadata">
<AssetFile Name="bcff8e9a-7cb7-4d09-abd2-f04a83df1be1.mp4" Size="383631" Duration="PT5.568S" NumberOfStreams="2" FormatNames="mov,mp4,m4a,3gp,3g2,mj2" FormatVerboseName="QuickTime / MOV" StartTime="PT0S" OverallBitRate="551">
<VideoTracks>
<VideoTrack Id="1" Codec="h264" CodecLongName="H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10" TimeBase="1/90000" NumberOfFrames="166" StartTime="PT0S" Duration="PT5.533S" FourCC="avc1" Profile="Constrained Baseline" Level="3.0" PixelFormat="yuv420p" Width="560" Height="320" DisplayAspectRatioNumerator="0" DisplayAspectRatioDenominator="1" SampleAspectRatioNumerator="0" SampleAspectRatioDenominator="1" FrameRate="30" Bitrate="465" HasBFrames="0">
<Disposition Default="1" Dub="0" Original="0" Comment="0" Lyrics="0" Karaoke="0" Forced="0" HearingImpaired="0" VisualImpaired="0" CleanEffects="0" AttachedPic="0" />
<Metadata key="creation_time" value="2010-03-20T21:29:11.000000Z" />
<Metadata key="language" value="und" />
<Metadata key="encoder" value="JVT/AVC Coding" />
</VideoTrack>
</VideoTracks>
<AudioTracks>
<AudioTrack Id="2" Codec="aac" CodecLongName="AAC (Advanced Audio Coding)" TimeBase="1/48000" NumberOfFrames="261" StartTime="PT0S" Duration="PT5.568S" SampleFormat="fltp" ChannelLayout="mono" Channels="1" SamplingRate="48000" Bitrate="83" BitsPerSample="0">
<Disposition Default="1" Dub="0" Original="0" Comment="0" Lyrics="0" Karaoke="0" Forced="0" HearingImpaired="0" VisualImpaired="0" CleanEffects="0" AttachedPic="0" />
<Metadata key="creation_time" value="2010-03-20T21:29:11.000000Z" />
<Metadata key="language" value="eng" />
</AudioTrack>
</AudioTracks>
<Metadata key="major_brand" value="mp42" />
<Metadata key="minor_version" value="0" />
<Metadata key="compatible_brands" value="mp42isomavc1" />
<Metadata key="creation_time" value="2010-03-20T21:29:11.000000Z" />
<Metadata key="encoder" value="HandBrake 0.9.4 2009112300" />
</AssetFile>
</AssetFiles>
--1b6c2d6e-53d6-414c-bb1b-681ff9c766f0--
I'm aware that there are other ways to upload xml data, but I'd prefer to keep the xml parsing on the api side of things, if possible. Thanks!
Problem was solved when I removed the [FromRoute] attribute from the IFormFile parameter and the [ApiController] attribute (not shown in code) from the MVC controller. So as not to disrupt functionality on the controller, I'll be creating a new controller specifically for the UpdateDuration() action.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.