Home > Blockchain >  Bad Request when trying POST in ASP .NET
Bad Request when trying POST in ASP .NET

Time:10-10

I have quite simple system: ASP .NET Core server which is hosted on domain.ru. In API controller there I have 2 methods:

    [HttpGet("{id}")]
    public string Get(int id)
    {
        try
        {
            using (FileStream fstream = new FileStream(string.Format(@"{0}\data{1}.txt", _path, id.ToString()), FileMode.OpenOrCreate))
            {
                byte[] array = System.Text.Encoding.Default.GetBytes(id.ToString());
                fstream.Write(array, 0, array.Length);
                return "It's ok!";
            }
        }
        catch
        {
            return "Something went wrong";
        }
    }
    [HttpPost]
    public string Post(string resolvedString)
    {
        try
        {
            using (FileStream fstream = new FileStream(string.Format(@"{0}\dataPost.txt", _path), FileMode.OpenOrCreate))
            {
                byte[] array = System.Text.Encoding.Default.GetBytes(resolvedString);
                fstream.Write(array, 0, array.Length);
                return "It's ok!";
            }
        }
        catch
        {
            return "Something went wrong";
        }
    }

So basically both of them are just creating text files in the _path directory. The part that i can't understand is when I try to call Get method by url domain.ru/api/values/1 I can see the file which was created in _path directory and I have response "It's ok!". That's how I call Get:

        var client = new HttpClient();
        client.BaseAddress = new Uri(uri);
        HttpResponseMessage response = await client.GetAsync("api/values/1");
        string result = await response.Content.ReadAsStringAsync();
        textBox1.Text = result.ToString();

But when I try the same with Post I get either Bad Request when I do it with C# or "Something went wrong" when I do it with Postman. That's the way how I call Post

        var client = new HttpClient();
        client.BaseAddress = new Uri(uri);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        MultipartFormDataContent content = new MultipartFormDataContent();
        StringContent str = new StringContent("1");
        content.Add(str);
        HttpResponseMessage response = await client.PostAsync("api/values/", content);
        string returnString = await response.Content.ReadAsStringAsync();
        MessageBox.Show(returnString);

Here's what the request shows when I try to manually debug this

And the most fun part. When I try to do all the same actions when my server is hosted on IIS (localserver) it works just fine! I' really don't know what I am doing wrong. Please, help.

UPD. Thanks to Jonathan, I asked my hoster to disable ModSecurity in Plesk and the above code started to work after replacing [HttpPost] by [HttpPost("{resolvedString}")]. So far so good!

Then I tried to send a zip archive to the server. Here is the server's controller code:

    [HttpPost]
    public string ImportZip(IFormFile file)
    {
        DirectoryInfo dirInfo = new DirectoryInfo(_extractPath);
        try
        {
            foreach (FileInfo myfile in dirInfo.GetFiles())
            {
                myfile.Delete();
            }
            string path = _path   "tmp.zip";
            if (Request.HasFormContentType)
            {
                var form = Request.Form;
                foreach (var formFile in form.Files)
                {
                    using (var fileStream = new FileStream(path, FileMode.Create))
                    {
                        formFile.CopyTo(fileStream);
                    }
                    ZipFile.ExtractToDirectory(_path   "tmp.zip", _extractPath);
                }
            }
            return "It's OK! At least we've entered the method.";
        }
        catch
        {
            return "Oh no no no...";
        }

    }

And that's how I call it from the client:

        string filepath = _zipFile;
        string filename = _fileName;
        var client = new HttpClient();
        client.BaseAddress = new Uri(uri);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        MultipartFormDataContent content = new MultipartFormDataContent();
        ByteArrayContent fileContent = new ByteArrayContent(File.ReadAllBytes(filepath));
        content.Add(fileContent, "file", filename);
        HttpResponseMessage response = await client.PostAsync("File/ImportZip/", content);
        string result = await response.Content.ReadAsStringAsync();
        textBox1.Text = result;

Once again, it works as it should when I run both server and client on my computer. I can see downloaded archive and extracted files in destination directories. But when I upload my server to hosting and try to execute my query once again, I get the same error: an example of an error

CodePudding user response:

Well, seems like I found an answer myself. Will leave it here so it can help someone (maybe me in the future).

Code of the client's send method:

        string uri = "https://example.com/controller/action/";
        string zipFile = @"C:\Path\To\Your\File.txt";
        string response;
        using (WebClient client = new WebClient())
        {
            response = Encoding.Default.GetString(client.UploadFile(uri, zipFile));
        }
        MessageBox.Show(response);

Here we just composing a request and sending a file. The path and url are hardcoded for ex.

Code of the server's save method:

[HttpPost]
    public string ImportZip(IFormFile file)
    {
        try
        {
            string path = _path   "tmp.zip";
            if (Request.HasFormContentType)
            {
                var form = Request.Form;
                foreach (var formFile in form.Files)
                {
                    using (var fileStream = new FileStream(path, FileMode.Create))
                    {
                        formFile.CopyTo(fileStream);
                    }
                }
                return "Done";
            }
            return "Empty request";
        }
        catch
        {
            return "No access";
        }
    }

As long as I send only one file and also I know its extension and I want it to be called "tmp", I hardcode it's name and extension. You can take file's default name/extension to save it as is. Then I save all the files in request into a chosen _path directory.

Basically, that's it.

  • Related