How to specify date format in RestSharp request - restsharp

I have this piece of code:
var client = new RestClient(fullUri);
var request = new RestRequest(GetMethod(method));
client.UseSerializer(
() => new RestSharp.Serialization.Json.JsonSerializer { DateFormat = "yyyy-MM-dd HH:mm:ss" }
);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Accept", "application/json");
if (body != null)
request.AddJsonBody(body);
var response = client.Execute(request);
if (response.ErrorException != null)
throw response.ErrorException;
return JsonConvert.DeserializeObject<ResponseData>(response.Content);
Note the
client.UseSerializer(
() => new RestSharp.Serialization.Json.JsonSerializer { DateFormat = "yyyy-MM-dd HH:mm:ss" }
);
I have added that code because I need the date format to be yyyy-MM-dd HH:mm:ss instead of yyyy-MM-ddTHH:mm:ss.zzzzz (the default)
RestRequest.DateFormat is obsolete.
When the calling is made, I saw that a date is passed using the default format, instead of the custom one.
How can I do it?

I will suggest rewrite your code. Here my comments and example:
First, if you try to use this format for DateTime yyyy-MM-dd HH:mm:ss you will get a validation error from web API service when you try to send a request.
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"00-a0c978c054625441b8ddf4c552b0f34c-314723fc8ce3ac4e-00",
"errors":{
"$.DateTime":[
"The JSON value could not be converted to System.DateTime. Path: $.DateTime | LineNumber: 0 | BytePositionInLine: 33."
]
}
}
This means - you use incorrect format for DateTime. You should use this format "yyyy-MM-ddTHH:mm:ss". Read more in question The JSON value could not be converted to System.DateTime.
Don't forget add T because parsers use ISO_8601
Second, I would highly recommend do not use JsonSerializer from RestSharp, because I faced different problems with it. I highly recommend to use System.Text.Json from Microsoft or Newtonsoft.Json. Read more about System.Text.Json or Newtonsoft.Json.
Third, let's code! My example of web api service.
[HttpGet]
public string Test()
{
var client = new RestClient("your url");
var request = new RestRequest(Method.POST);
var body = new SimpleRequestBody
{
DateTime = DateTime.Now
};
var json = JsonConvert.SerializeObject(body,
new JsonSerializerSettings()
{
DateFormatString = "yyyy-MM-ddTHH:mm:ss"
});
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Accept", "application/json");
if (body != null)
request.AddParameter("application/json", json, null, ParameterType.RequestBody);
var response = client.Execute(request);
// response.ErrorException -> Could not handle bad request
// Better to user IsSuccessful property
if (!response.IsSuccessful)
throw new Exception(response.Content);
return response.Content;
}
public class SimpleRequestBody
{
public DateTime DateTime { get; set; }
}
Example of client web api code:
[HttpPost]
public ActionResult Post([FromBody] SimpleResponse response)
{
var result = $"OK result from another web api. DateTime {response.DateTime}";
return Ok(result);
}
public class SimpleResponse
{
public DateTime DateTime { get; set; }
}
}
Results

Related

Error in ASP.NET Core MVC and Web API project

I have an ASP.NET Core MVC and also Web API project.
This error occurs when I try to send project information to the API (of course API works fine and I do not think there is a problem):
UnsupportedMediaTypeException: No MediaTypeFormatter is available to read a "TokenModel" object of "text / plain" media content.
My code is:
public class TokenModel
{
public string Token { get; set; }
}
and in AuthController I have:
var _Client = _httpClientFactory.CreateClient("MyApiClient");
var jsonBody = JsonConvert.SerializeObject(login);
var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = _Client.PostAsync("/Api/Authentication", content).Result;
if (response.IsSuccessStatusCode)
{
var token = response.Content.ReadAsAsync<TokenModel>().Result;
}
The error occurs on this line:
var token = response.Content.ReadAsAsync<TokenModel>().Result;
HomeController:
public IActionResult Index()
{
var token = User.FindFirst("AccessToken").Value;
return View(_user.GetAllUsers(token));
}
UserRepository:
public List<UserViewModel> GetAllUsers(string token)
{
_client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var res = _client.GetStringAsync(UrlMyApi).Result;
List<UserViewModel> users = JsonConvert.DeserializeObject<List<UserViewModel>>(res);
return users;
}
Your API is returning content-type of text/plain and none of the default media type formatters(MediaTypeFormatter) which ReadAsAsync<string>() will try to use support parsing it as is. They work with JSON/XML. You can go a couple of ways but maybe the easiest is to read the content as string and deserialize it after:
var tokenJSON = response.Content.ReadAsStringAsync().Result;
var token = JsonConvert.DeserializeObject<TokenModel>(tokenJSON);
Also, as you're using the Async methods, you should be returning Task from your actions and await the result instead of using .Result as you're just creating overhead currently.
var tokenJSON = await response.Content.ReadAsStringAsync();
var token = JsonConvert.DeserializeObject<TokenModel>(tokenJSON);

Is there any in-built function/method to return, IActionResult/ActionResult instead of HttpResponseMessage in .Net Core 3.1

My Action method is returning HttpResponseMessage but, I want to get rid off Microsoft.AspNetCore.Mvc.WebApiCompatShim NuGet Package (which is basically provided to bridge the gap while porting Asp.Net Web API code into .Net Core) and use IActionResult/ActionResult instead of HttpResponseMessage.
My Action method looks like this:
[HttpGet]
[Route("GetTemplate")]
public async Task<HttpResponseMessage> GetTemplate(string id) {
var userAgent = this.Request.Headers.UserAgent;
bool IsWindows = true;
if(userAgent.ToString().ToLower().Contains("apple")) {
IsWindows = false; //false
}
var template = await _templateService.GetTemplateContent(id);
HttpResponseMessage responseMsg = new HttpResponseMessage();
if(IsWindows) {
responseMsg.Content = new StringContent(JsonConvert.SerializeObject(template));
responseMsg.RequestMessage = Request;
responseMsg.StatusCode = HttpStatusCode.OK;
responseMsg.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/json");
} else {
responseMsg.Content = new ByteArrayContent(template.ContentBytes);
responseMsg.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileNameStar = template.Name };
responseMsg.Content.Headers.Add("x-filename", template.Name);
responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
responseMsg.Content.Headers.ContentLength = template.ContentBytes.Length;
responseMsg.RequestMessage = Request;
responseMsg.StatusCode = HttpStatusCode.OK;
}
return (responseMsg);
}
Since you aren’t doing anything fancy there, you can translate your return object directly into corresponding action results here. In your case, you want a JsonResult and a FileResult with a custom response header:
[HttpGet]
[Route("GetTemplate")]
public async Task<HttpResponseMessage> GetTemplate(string id)
{
var userAgent = this.Request.Headers.UserAgent;
bool IsWindows = !userAgent.ToString().ToLower().Contains("apple");
var template = await _templateService.GetTemplateContent(id);
if (IsWindows)
{
return Json(template);
}
else
{
Response.Headers.Add("x-filename", template.Name);
return File(template.ContentBytes, "application/octet-stream", template.Name);
}
}
There are a lot similar utility methods on the Controller and ControllerBase type that help you create a variety of different response messages. For most use cases, there should be a built-in way to produce the response.
1stly change the signature of your action to this:
public async Task<IActionResult> GetTemplate
You will then return your data in the response something like this return Ok(data). You do not have to serialize your data, you can send a POCO class. This would represent .StatusCode = HttpStatusCode.OK
If you want to add extra headers to your response, you will do so using the Response field from ControllerBase. Eg. Response.Headers.Add for adding key value pairs to your Response header.

Storing An Image In SQL Server

I need to create a procedure in SQL server that takes a web URL of an image and converts it to VARBINARY, and after that: store in a column called "personqr_Image" in table "tblPersons".
I created a procedure "getPersonQrCode" that returns a URL of a unique QR code (450x450 image), and using that URL I need to convert it to VARBINARY data type in order to store it in my SQL DB.
Unfortunately I haven't really found a solution online, maybe because I am not very familiar with the subject.
You can't do this purely in TSQL, as it doesn't have any functions for browsing the web and handling http requests and responses. If you have to do this IN SQL Server, you'll need to write a CLR procedure.
Here is a CLR function that will allow you to submit HTTP requests
public class RestClient
{
[SqlFunction(DataAccess = DataAccessKind.Read)]
public static string Submit(string url, string data, string contentType, string
method = "POST",
string httpHeaderCredentials = "")
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
var request = (HttpWebRequest) WebRequest.Create(url);
//Add header credentials if required
if (!string.IsNullOrEmpty(httpHeaderCredentials))
{
request.Headers.Add("Authorization: " + httpHeaderCredentials);
}
request.ContentType = contentType;
request.Method = method;
if (request.Method == "PATCH")
{
//http://stackoverflow.com/questions/31043195/rest-api-patch-request
request.ServicePoint.Expect100Continue = false;
}
if (method == "POST" || method == "PATCH")
{
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(data);
streamWriter.Flush();
streamWriter.Close();
}
}
var httpResponse = request.GetResponse();
using (var responseStream = httpResponse.GetResponseStream())
{
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
return reader.ReadToEnd().Replace("\n", string.Empty);
}
}
}
}
catch (Exception ex)
{
if (SqlContext.Pipe != null)
{
SqlContext.Pipe.Send(ex.Message);
}
}
return "";
}

Twitter new DM API, legacy method of authorization not working

We are trying to implement Twitter new DM API from Salesforce. We are sending our the JSON request in the body as mentioned in documentation but the legacy method for Oauth authorization is not working. Any help is greatly appreciated.
To add, I am sending a DM from salesforce to twitter, So
1) I am setting the request body in JSON.
2) I am doing a POST.
3) I am hitting the endpoint at 'https://api.twitter.com/1.1/direct_messages/events/new.json'
4) Oauth2, getting the access token(successfully)
5) Setting header as ('Content-Type', 'application/json').
6) Creating Authorization header as twitter mentions using consumer key, Nonce, Signature, Signature method, Timestamp, Version. Building the same as in "Guide" section of developer.twitter.com/en/docs/basics/authentication/guides/
7) On running the error code "{"errors":[{"code":32,"message":"Could not authenticate you."}]}".
Another important information that I had been using twitter old API to send DM that works perfect, only difference is it sends the request body in URL parameters instead of JSOn body but the authorization method remains same. As some new Functionality can only be achieved via Twitter New API and according to documentation the body needs to be sent via JSON format. Therefore the request part is changed but authorization is same.
Sample code:-
String accTok = 'redacted';
String conKey = 'redacted';
String conSec = 'redacted';
String accTokSec = 'redacted';
String theTweet = 'Hello world!';
String screenName ='some_test_username';
String jsonString = TwitterJsonReqGenerator.generateJSON(theTweet, screenName);
system.debug('JSON string ='+jsonString);
httpRequest newReq = new httpRequest();
newReq.setBody(jsonString);
newReq.setMethod('POST');
newReq.setEndpoint('https://api.twitter.com/1.1/direct_messages/events/new.json');
//Generate Nonce
string oAuth_nonce = EncodingUtil.base64Encode(blob.valueOf(string.valueOf(Crypto.getRandomInteger()+system.now().getTime())+string.valueOf(Crypto.getRandomInteger()))).replaceAll('[^a-z^A-Z^0-9]','');
map<String, String> heads = new map<String, String>{
'oauth_token'=>accTok,
'oauth_version'=>'1.0',
'oauth_nonce'=>oAuth_nonce,
'oauth_consumer_key'=>conKey,
'oauth_signature_method'=>'HMAC-SHA1',
'oauth_timestamp'=>string.valueOf(system.now().getTime()/1000)
};
//Alphabetize
string[] paramHeads = new string[]{};
paramHeads.addAll(heads.keySet());
paramHeads.sort();
string params = '';
for(String encodedKey : paramHeads){
params+=encodedKey+'%3D'+heads.get(encodedKey)+'%26';
}
//params+='status'+percentEncode('='+percentEncode(theTweet));
params+=percentEncode(theTweet);
//Build the base string
string sigBaseString = newReq.getMethod().toUpperCase()+'&'+EncodingUtil.urlEncode(newReq.getEndpoint(),'UTF-8')+'&'+params;
system.debug('signatureBaseString == '+sigBaseString);
//calculate signature
string sigKey = EncodingUtil.urlEncode(conSec,'UTF-8')+'&'+EncodingUtil.urlEncode(accTokSec,'UTF-8');
blob mac = crypto.generateMac('hmacSHA1', blob.valueOf(sigBaseString), blob.valueOf(sigKey));
string oauth_signature = EncodingUtil.base64Encode(mac);
heads.put(EncodingUtil.urlEncode('oauth_signature','UTF-8'), EncodingUtil.urlEncode(oauth_signature,'UTF-8'));
//build the authorization header
paramHeads.clear();
paramHeads.addAll(heads.keySet());
paramHeads.sort();
string oAuth_Body = 'OAuth ';
for(String key : paramHeads){
oAuth_Body += key+'="'+heads.get(key)+'", ';
}
oAuth_Body = oAuth_Body.subString(0, (oAuth_Body.length() - 2));
newReq.setHeader('Authorization', oAuth_Body);
system.debug('Authroization Header == '+oAuth_Body);
newReq.setHeader('Content-Type', 'application/json');
httpResponse httpRes = new http().send(newReq);
String response = httpRes.getBody();
system.debug(response);
Thanks
Prateek
I've written Twitter libraries and applications in the past, and the bst advice that I can give you is to use an existing implementation of OAuth instead of attempting to write your own. Re-implementing OAuth in new code is re-inventing the wheel, and it's a wheel that hates you. There are a number of robust and mature OAuth libraries that are free and/or open source.
Just happened to stumble on your query. I am posting a code(C#) (though it is a bit late) which worked for me to send DM to Twitter using the new API. Hope this helps. Thanks to Danny Tuppeny's blog
namespace TweetApp.Droid
{
class TweetDM
{
const string TwitterApiBaseUrl = "https://api.twitter.com/1.1/";
readonly string consumerKey, consumerKeySecret, accessToken, accessTokenSecret;
readonly HMACSHA1 sigHasher;
readonly DateTime epochUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public TweetDM(string consumerKey, string consumerKeySecret, string accessToken, string accessTokenSecret)
{
this.consumerKey = consumerKey;
this.consumerKeySecret = consumerKeySecret;
this.accessToken = accessToken;
this.accessTokenSecret = accessTokenSecret;
sigHasher = new HMACSHA1(new ASCIIEncoding().GetBytes(string.Format("{0}&{1}", consumerKeySecret, accessTokenSecret)));
}
public Task<string> Tweet(string text, string recipientID)
{
JSONObject jasonobject = new JSONObject
{
#event = new TwitterEvent
{
type = "message_create",
message_create = new msg_create
{
target = new tgt
{
recipient_id = recipientID
},
message_data = new msg_data
{
text = text
}
},
}
};
var JsonString =JsonConvert.SerializeObject(jasonobject);
var data4Auth = new Dictionary<string, string> {
};
return PrepareAuth("direct_messages/events/new.json", data4Auth, JsonString);
}
Task<string> PrepareAuth(string url, Dictionary<string, string> data4Auth, string JsonString)
{
var fullUrl = TwitterApiBaseUrl + url;
var timestamp = (int)((DateTime.UtcNow - epochUtc).TotalSeconds);
data4Auth.Add("oauth_consumer_key", consumerKey);
data4Auth.Add("oauth_signature_method", "HMAC-SHA1");
data4Auth.Add("oauth_timestamp", timestamp.ToString());
data4Auth.Add("oauth_nonce", "a"); // Required, but Twitter doesn't appear to use it, so "a" will do.
data4Auth.Add("oauth_token", accessToken);
data4Auth.Add("oauth_version", "1.0");
// Generate the OAuth signature and add it to our payload.
data4Auth.Add("oauth_signature", GenerateSignature(fullUrl, data4Auth));
// Build the OAuth HTTP Header from the data.
string oAuthHeader = GenerateOAuthHeader(data4Auth);
// Setting Content details
var JsonData = new StringContent(JsonString, Encoding.UTF8, "application/json");
return SendRequest(fullUrl, oAuthHeader, JsonData);
}
string GenerateSignature(string url, Dictionary<string, string> data)
{
var sigString = string.Join(
"&",
data
.Union(data)
.Select(kvp => string.Format("{0}={1}", Uri.EscapeDataString(kvp.Key), Uri.EscapeDataString(kvp.Value)))
.OrderBy(s => s)
);
var fullSigData = string.Format(
"{0}&{1}&{2}",
"POST",
Uri.EscapeDataString(url),
Uri.EscapeDataString(sigString.ToString())
);
return Convert.ToBase64String(sigHasher.ComputeHash(new ASCIIEncoding().GetBytes(fullSigData.ToString())));
}
string GenerateOAuthHeader(Dictionary<string, string> data)
{
return "OAuth " + string.Join(
", ",
data
.Where(kvp => kvp.Key.StartsWith("oauth_"))
.Select(kvp => string.Format("{0}=\"{1}\"", Uri.EscapeDataString(kvp.Key), Uri.EscapeDataString(kvp.Value)))
.OrderBy(s => s)
);
}
async Task<string> SendRequest(string fullUrl, string oAuthHeader, StringContent jsondata)
{
using (var http = new HttpClient())
{
http.DefaultRequestHeaders.Add("Authorization", oAuthHeader);
var httpResp = await http.PostAsync(fullUrl, jsondata);
var respBody = await httpResp.Content.ReadAsStringAsync();
return respBody;
}
}
}
// Classes for creating JSON body
public class JSONObject
{
public TwitterEvent #event;
}
public class TwitterEvent
{
public string type;
public msg_create message_create;
}
public class msg_create
{
public tgt target;
public msg_data message_data;
}
public class tgt
{
public string recipient_id;
}
public class msg_data
{
public string text;
}
}
To call:
var twitter = new TweetDM(consumerKey, consumerKeySecret, accessToken, accessTokenSecret);
await twitter.Tweet(textBox1.Text, textBox2.Text);

MVC aynchronous method

I am working on a MVC project that submits a request via a third party.
In my controller, I have a SubmitClaims() action that receive ajax request and then calls RunAsync(). RunAsync submits a request by using HttpClient.
I am not sure if I did a right thing here.
Also I have two version of SubmitClaims(), both work. But I don't know which version is better.
version 1
[HttpPost]
public async Task<string> SubmitClaims()
{
string result = "";
result = await RunAsync();
return result;
}
version 2 learn from Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'
[HttpPost]
public async Task<string> SubmitClaims()
{
return await Task.Run(() =>
{
return RunAsync();
});
}
static async Task<string> RunAsync()
{
string result = "Failed.";
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://peter:8001/internal/uickpost");
client.DefaultRequestHeaders.Add("contenttype", "application/xml");
client.DefaultRequestHeaders.Add("hiconline.protocol.content.role", "REQUEST");
client.DefaultRequestHeaders.Add("hiconline.protocol.content.transactionid", "asdfsdf");
client.DefaultRequestHeaders.Add("hiconline.protocol.remote.contenttype", "TestDataType");
client.DefaultRequestHeaders.Add("hiconline.protocol.remote.mode", "P");
client.DefaultRequestHeaders.Host = "peter:8001";
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
string opv = "Test Data";
HttpContent _content = new StringContent(opv);
_content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
_content.Headers.Add("contenttype", "TestDataType");
HttpResponseMessage response1 = await client.PostAsync(client.BaseAddress, _content);
if (response1.IsSuccessStatusCode)
{
Uri gizmoUrl = response1.Headers.Location;
result = response1.Content.ReadAsStringAsync().Result;
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
}
Option 1 is better. RunAsync() already returns a task, so why create another one?
Even better would be return await RunAsync();. Even better would just be calling RunAsync directly, since the wrapper doesn't add anything.