0

フォームに添付ファイルを取り込む MVC Web API があり、アップロードにはテキストと整数フィールドも必要です。フィールドは、アップローダーを確認するための (文字列) userId と、添付ファイルをデータベース内の要求に接続するための (int) requestId です。現在は機能していますが、フォーム送信のパラメーターとしてではなく、リクエストからフィールドを取得する必要があるマルチパートフォームデータを使用しています。私の問題は、ファイルを保存するときに、(フォームからの) requestId と (データベースからの) 添付ファイル ID を使用してファイルの名前を変更し、(requestId)-(attachmentId)-(fileName) を読み取る必要があることです。私が使用してきた方法では、ファイルをダウンロードしてからリクエストからデータを取得します。これは、プロバイダーが初期化されてファイルがダウンロードされる前に常に null を返すためです。次に、データベースとファイル システムの両方でファイルの名前を変更します。誰かがこれを行うためのより良い方法を持っていることを望んでいたので、適切な変数で名前を変更することを1つのステップで行うことができます。

Here is what I have right now for my controller

public async Task<HttpResponseMessage> PostFormData()
    {
        const string folderName = "uploads";
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException((HttpStatusCode.UnsupportedMediaType));
        }
        var rootUrl = Request.RequestUri.AbsoluteUri.Replace(Request.RequestUri.AbsolutePath, String.Empty);
        // this is needed to create an attachment and get the attachment id for the file
        var value = new Attachment {UserId = "1", RequestId = 1};
        value = _dataManager.CreateNewAttachment(value);

        string root = HttpContext.Current.Server.MapPath("~/" + folderName);
        // this is where the provider gets initialized and also where the file is actually downloaded
        // in here I have it set up to rename the file but I can't seem to get the parameters needed for the file name before hand
        var provider = new CustomMultipartFormDataStreamProvider(root, value.CreditRequestId, value.Id);

        try
        {
            // this is the command that allows me to get the data from the inputs on the form, 
            // but it requires the initialized provider which downloaded the file to get it
            await Request.Content.ReadAsMultipartAsync(provider);
            // and here is wher I actually get the input parameters I needed
            foreach (var key in provider.FormData.AllKeys)
            {
                foreach (var val in provider.FormData.GetValues(key))
                {
                    //Trace.WriteLine(string.Format("{0}: {1}", key, val));
                    if (key == "requestId")
                    {
                        value.CreditRequestId = int.Parse(val);
                    }
                    if (key == "userId")
                    {
                        value.UserId = val;
                    }
                }
            }
            // below here is where I have it checking security against the userId, destroying the file if it is determined to be unsafe
            // and where I rename the file as well as modify the database with the proper content for the attachment

Below is my Custom multipart form data stream provider that I initialized to get the file and change the name but before this I am unable to get the parameters I need to do this properly without having to revisit the file and rename it

public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
    public int RequestId;
    public int AttachmentId;

    public CustomMultipartFormDataStreamProvider(string path, int requestId, int attachmentId)
        : base(path)
    {
        RequestId = requestId;
        AttachmentId = attachmentId;
    }

    public override string GetLocalFileName(HttpContentHeaders headers)
    {
        //int requestId = 0;
        //int attachmentId = 0;
        var name = !string.IsNullOrEmpty(headers.ContentDisposition.FileName)
                       ? RequestId + "-" + AttachmentId + "-" + headers.ContentDisposition.FileName
                       : RequestId + "-" + AttachmentId + "-NoName";
        return name.Replace("\"", string.Empty);
    }

I have searched google and SO looking for an answer to this and I thought I had a few answers but they didn't seem to work, I have tried getting the data from within the provider but it always returns null. Please if anyone has a solution to this it would be greatly appreciated

4

1 に答える 1

0

他の誰かが自分で答えを探している場合に備えて、ファイルを作成する前に httpContext を照会しました.Web APIを使用すると、UIから送信されたフォームデータを読み取ることができます

 public async Task<HttpResponseMessage> PostFormData()
    {
        const string folderName = "uploads";
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException((HttpStatusCode.UnsupportedMediaType));
        }
        var rootUrl = Request.RequestUri.AbsoluteUri.Replace(Request.RequestUri.AbsolutePath, String.Empty);

        // this is where I get the form information now prior to actually recieving the file
        int requestId = int.Parse(HttpContext.Current.Request.Form["requestId"]);
        string userId = HttpContext.Current.Request.Form["userId"];


        var value = new Attachment {UserId = userId, RequestId = requestId};
        value = _dataManager.CreateNewAttachment(value);


        string root = HttpContext.Current.Server.MapPath("~/" + folderName);

        var provider = new CustomMultipartFormDataStreamProvider(root, value.RequestId, value.Id);

        try
        {

            await Request.Content.ReadAsMultipartAsync(provider);

            var httpRequest = HttpContext.Current.Request;

            foreach (string file in httpRequest.Files)
            {
            var postedFile = httpRequest.Files[file];
            var filePath = rootUrl + "/" + folderName + "/";

            value.Path = filePath + value.RequestId + "-" + value.Id + "-" + postedFile.FileName;
            value.FileName = value.RequestId + "-" + value.Id + "-" + postedFile.FileName;

            }

結局のところ、ファイルが安全かどうかを判断するビジネス ロジックを含めることができ、サーバー上でファイルの名前を変更するためにファイルの移動関数を呼び出す必要はありません。それはそれをもう少し安定させます。

于 2013-09-03T16:43:10.893 に答える