I'm building a web Api to catalog my firms bug report onto a server, and I'm having trouble with the post request that I'm doing.
As I've coded the clients they should be either sending bug reports that are formatted like this
public partial class JitCollect {
public DateTime? Timestamp { get; set; }
public string Jit { get; set; }
public int? ProjectId{ get; set; }
}
or they could be sending strings with status reports like "OK" or whatever. My main problem is that if I send the bug reports as "application/x-www-form-urlencoded" and prepending a '=' to my body like I saw online, I lose the DateTime format that NewtonSoft is expecting on the other side:
before "2018-08-14T08:50:17.5608444+02:00"
after "2018-08-14T08:50:17.5608444 02:00"
I could hardcode something to put the '+' back but that's beside the point, I'm interested in how to properly accomplish what I'm trying to do.
if I instead try to send the data as "application/json", I always get empty data on the other side even specifying the from body attribute and the object type (which is not ideal for me because I want to be able to send plain strings as well)
[HttpPost]
public string Post([FromBody] List < JitCollect > jsonPost)
any idea what is the best way to do this? here's one of the many post functions I tried to use
public static void postRequest(string data, string address) {
using (var client = new HttpClient()) {
client.BaseAddress = new Uri(address);
data = $"={data}";
//client.DefaultRequestHeaders.Add("token", token);
var buffer = System.Text.Encoding.UTF8.GetBytes(data);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
//byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = client.PostAsync("", byteContent).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
}
}
I made a test with asp.net core web api, it passes the datetime correctly.
Controller
[HttpPost]
public object Post([FromBody]List<JitCollect> jsonPost)
{
var resul = jsonPost.FirstOrDefault().Timestamp.Value.ToString("yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss.fffffffK");
return new List<JitCollect>() {
new JitCollect{ ProjectId = 1, Jit = "J1", Timestamp = DateTime.Now }
};
}
Request from postman
Result From Controller
Related
I have an enpoint that I send request via Postman form-data. Request has 2 keys.
message : string
file: File
this works ok. So, I want to send the same request in C# code. In c# I just need to choose file from local, somehow convert it to proper format, assign it to file property in request Model, I mean I can not change the logic how request is sent. I must not write additional logic to HttpRequest or MultipartFormDataContent etc (I can not even see this part how it is sent). Just need to add Model to this request body.
I have model RequestModel
public class RequestModel
{
[JsonProperty("message")]
public string Message {get; set; }
[JsonProperty("file")]
public whateverType File {get; set; }
}
message part works, so I need to assign local file to File property. how can I do that. I tried almost everything but it does not work. Thanks.
You don't need to keep the file in your model.
this is an example to post a model just by knowing the file name.
var model = new RequestModel();
// ... fill the model with some data
model.Message = "test";
model.File = #"c:\test.jpg";
using var httpClient = new HttpClient();
{
var form = new MultipartFormDataContent();
form.Add(new StringContent(model.Message), nameof(RequestModel.Message));
var bytes = File.ReadAllBytes(model.File);
form.Add(new ByteArrayContent(bytes, 0, bytes.Length), "profile_pic", "hello1.jpg");
var response = await httpClient.PostAsync("PostUrl", form);
response.EnsureSuccessStatusCode();
var sd = response.Content.ReadAsStringAsync().Result; // you should use await if your method is async ...
}
public class RequestModel
{
public string Message { get; set; }
public string File { get; set; } // simply use file-path
}
Hello I am attempting to use the HttpClient.GetAsync method to retrieve some information from my web API. I am unsure how to structure the query parameters for the GET request when needing to pass a list of complex objects. I am not necessarily tied to using query parameters, I am not sure if this would be a good case to just make it a POST and pass the data in the body? Overall I am just looking for either a better way to do this or some recommendations on how to proceed.
WEB API:
This is my WEB API code, as you can see I am passing in a list of VariantDTO and 2 simple parameters
[HttpGet]
[ResponseType(typeof(List<SchematicDTO>))]
[Route("api/schematic/GetSchematicsForMacroVariants")]
public HttpResponseMessage GetSchematicsForMacroVariants([FromUri]List<VariantDTO> dto, bool IncludeEngineered, bool IncludeStandard)
{
}
VariantDTO
This is what my DTO looks like.
public class VariantDTO
{
public string Id { get; set; }
public string Variant { get; set; }
}
MVC Controller
In my MVC controller is where I am attempting to call the WEB API. I have just started to use the asp.net web api for the first time and am getting a bit confused on how to go about passing this data?
public JsonResult GetSchematicsForSelectedVariants(List<VariantViewModel> ListOfVariants,bool GetEngineered, bool GetStandard)
{
List<SchematicViewModel> vms = new List<SchematicViewModel>(); //List of schematic vm we want to return
//Create DTO from View Model
List<VariantDTO> Dto = ListOfVariants.Select(x => new VariantDTO
{
Id = x.Id,
Variant = x.Variant
}).ToList();
using (var client = new HttpClient())
{
//---NOT SURE HOW TO PASS MY DTO and GetEngineered and GetStandard parameters????
var responseTask = client.GetAsync(ServerName + "/api/schematic/GetSchematicsForMacroVariants/");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsStringAsync().Result;
//Deserialize object
var deserialized = JsonConvert.DeserializeObject<List<SchematicDTO>>(readTask);
vms = deserialized.Select(x => new SchematicViewModel
{
FullPath = x.FullPath,
Id = x.Id
}).ToList();
}
}
return Json(vms, JsonRequestBehavior.AllowGet);
}
Any direction or suggestions would be fantastic as I am a bit lost.
Thank you!
I have been trying to find examples of CRUD Firebase database for C#. I have researched some websites and tried doing on my own, but not all are complete nor updated examples.
May I know if there is a complete example of such?
I have tried using HttpWebResponse to query from Firebase.
So this is my sample code
public void getUser()
{
var request = (HttpWebRequest)WebRequest.Create(apiUrl + "user.json?orderBy=\"email\"&equalTo=" + "\"" + userId + "\"");
request.Method = "GET";
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
var js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
var result = JsonConvert.DeserializeObject<List<User>>(objText);
}
}
}
My User class
public string email { get; set; }
public string firstName { get; set; }
public string #group { get; set; }
public string lastName { get; set; }
However, when I call getUser, it returns me null. But inside the objText, there is text in it.
E.g.
{"12345678":{"email":"user#hotmail.com","firstName":"Alan","group":"N","lastName":"Paul"}}
You are trying to get the User data from the Firebase database and you are able to get the data successfully too.
The issue is with the JSON deserialization. The JSON you are getting from Firebase can not be deserialized to List<User>. Also it can not be deserialized to a single object of User.
The reason for this is the format of the JSON. As per the JSON the target class should have a property with name 12345678 and the type of the property should be User. And your User class not like that. I assume that the value "12345678" is the userId.
What you can do is to convert the JSON to a dictionary with string as Key and User as value holding type and then get the User object from the dictionary.
Consider following code. (I am writing only necessary code here)
var objText = reader.ReadToEnd();
var usersDictionary = JsonConvert.DeserializeObject<Dictionary<string, User>>(objText);
// I assume that the value `12345678` represents the UserId.
// If my assumption is right, following code gives you the user object from the dictionary.
var result = usersDictionary[userId];
//this line of code may throw an exception coz the dictionary does not have the userId in it
// this could be due to Firebase did not return any data in "objText".
This way you can get the user object out or the response text from the Firebase.
I'm trying to pass my JSON to Web.API service. The sending works well with Fiddler when I set to POST and I get value inside [FromBody ] argument:
Http/1.1
User-Agent: Fiddler
content-type: application/json; charset=utf-8
Host: http://localhost:27701/api/myList
Content-Length: 883
But when I use this C# code to post JSON, then [FromBody ] argument is empty:
HttpContent content = new StringContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:27701/api/");
HttpResponseMessage response = client.PostAsync("myList", content).Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsAsync<string>().Result;
s = result;
}
The data part is the exact JSON in both Fiddler and my code and the controller called in both calls.
This is my JSON:
{
"Id":0,
"Count":0,
"StartDate":"\\/Date(-62135596800000)\\/",
"Address":{
"Id":0,
"State":"test",
"City":"test"
}
}
One thing is if I don't put ' (single quotation) in both side of string inside fiddler the [FromBody] argument is empty, but if i put those on C# sample the respond is 500 server error.
You haven't posted your receiving method code, but based on provided data it should be a method with one argument which is an object that represents your JSON. In this case you don't need to use FromBody attribute at all.
If you check this article you can find there that:
By default, Web API uses the following rules to bind parameters:
If the parameter is a “simple” type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int,
bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal,
and string, plus any type with a type converter that can convert from
a string.
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
I created a models based on your JSON:
public class Address
{
public int Id { get; set; }
public string State { get; set; }
public string City { get; set; }
}
public class RootObject
{
public int Id { get; set; }
public int Count { get; set; }
public string StartDate { get; set; } // Keeped as string for simplicity
public Address Address { get; set; }
}
And then really simple method that can receive such JSON:
public RootObject Post(RootObject req)
{
return req;
}
Then I tested it both with Fiddler:
Method:
POST
Headers:
Content-Type: application/json
Request Body:
{"Id":0,"Count":0,"StartDate":"\\/Date(-62135596800000)\\/","Address":{"Id":0,"State":"test","City":"test"}}
And C# code:
var data = "{\"Id\":0,\"Count\":0,\"StartDate\":\"\\/Date(-62135596800000)\\/\",\"Address\":{\"Id\":0,\"State\":\"test\",\"City\":\"test\"}}";
using (var client = new HttpClient())
{
HttpContent content = new StringContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response =
client.PostAsync("http://my.url", content).Result;
var result = response.Content.ReadAsStringAsync().Result;
}
In both cases I was able to get sent object back.
Some tips:
When you send JSON with Fiddler you should not use any escaping
for request body. Just enter valid JSON and that's it.
In C# code if you need to declare a string variable with JSON you
will need to use escaping. For example var json = "\"a\":\"b\""; or
var json = #"""a"":""b""";. If you received JSON from somewhere
else then you don't need to do nothing.
You should never encase JSON with ' chars.
I'm using ServiceStack for a while now and I'm very happy with the functionality it provides. Already implemented serveral services with it and it works like a charm.
Recently however I've faced a problem with calling other service with a sophisticated URL that has to be encoded properly.
The code is the following:
The Request:
[Route("/instruments/{Names}")]
internal class Request
{
public List<string> Names { get; set; }
}
And the method call:
var request = new Request { Names = list };
var c = new JsonServiceClient("http://host:12345/");
Response[] response;
try
{
response = c.Get<Response[]>(request);
}
catch (WebServiceException ex)
{
HandleWebException(ex, list);
yield break;
}
And now the problem is that sometimes the name can contain a special characters like space or /.
I'd like to have those propery encoded. For instance I'd like to be able to call the remote service with the following parameters: "D\S N" with is supposed to be encoded to "D%5CS%20N".
So the called URL should look something like this:
http://host:12345/instruments/D%5CS%20N
And now the problem is that JsonServiceClient does the bad encoding here.
What I call is actually:
http://host:12345/instruments/D/S%20N
With is obviously wrong.
Any help how to sort this out is appeciated.
You shouldn't register complex types like List<T> in the PathInfo, try with a single string:
[Route("/instruments/{Name}")]
public class Request
{
public string Name { get; set; }
}
Or take it out of the /pathinfo so it will get serialized as a complex type on the QueryString:
[Route("/instruments")]
public class Request
{
public List<string> Names { get; set; }
}
I believe ServiceStack could be improved here.
If I use a request DTO defined like this:
[Route("/hello/{Name}/{Message}")]
public class Hello
{
public string Name { get; set; }
public string Message { get; set; }
}
Then a client calling like this:
var resp = cli.Get(new Hello { Message = "test", Name = "foo/bar" });
will fail. Same happens if I replace the slash with a backslash.
I have made a patch to ServiceStack that fixes this behaviour (works for backslash too), so that Name will be correctly encoded client side and decoded server side. Demis, is this something you might be interested in taking a look at?
BTW this works fine out-of-the-box with Java Jersey.....
I am encountering the same problem. My string is not a complex object. Just a string with a slash in it. It seems like ServiceStack is in fact receiving the URL encoded string correctly. Servicestack then appears to be decoding the URL encoded string before it passes it to routing (this is just a guess on my part) , instead of using the Route information in the request DTO to first determine which part of the URL is routing and which part is a parameter, then routing, then decoding the URL encoded parameter. I receive an error from service stack like so:
Handler for Request not found (404):
Request.HttpMethod: GET
Request.PathInfo: /QuoteFeed/GetQuote/ACO/X CN
Request.QueryString:
Request.RawUrl: /QuoteFeed/GetQuote/ACO%2FX%20CN
Request is defined as follows:
[Route("/QuoteFeed/GetQuote/{Symbol}", Summary = "Retreive a price quote for the requested symbol.")]
public class GetQuote : IReturn<QuoteDataResponse>
{
[DataMember, ProtoMember(1)]
[ApiMember(Name = "Symbol",
Description = "The symbol, in the providers given format, for which a quote should be given.",
DataType = "string",
IsRequired = true)]
public string Symbol { get; set; }
}
Seems fragile to require the client to replace slashes with some other special character which the service would swap back to a slash. Is the only way around this to force the request through POST?
Edit 1
This is my best attempt at getting this to work:
On the client side:
dim client = new JsonServiceClient (My.Settings.MarketDataServiceUri)
dim request = New GetQuote
request.Symbol = WebUtility.UrlEncode(txtBoxSymbol.Text.ToUpperInvariant)
On the server side (in AppHost.Init):
base.RequestBinders.Add(typeof(GetQuote), httpReq =>
{
var requestPath = string.Empty;
if (typeof(GetQuote).GetCustomAttributes(typeof(RouteAttribute), true
).FirstOrDefault() is RouteAttribute dnAttribute)
{
requestPath = dnAttribute.Path;
}
var routePath = requestPath;
var paramIndex = requestPath.IndexOf("{");
if (paramIndex > 0)
{
routePath = requestPath.Substring(0, paramIndex);
}
return new GetQuote
{
Symbol = WebUtility.UrlDecode(httpReq.PathInfo.Replace(routePath, string.Empty))
};
});
This is really ugly, but I can't find any other way around this. The symbol being passed in must have the slashes since that is the format required by the downstream quote provider and is what the users expect to enter. Is this the best way to do this?