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.