RestSharp 106.xx client can invoke HttpPut with variable string array service as version 108.xx - c#

Server code:
Rest2ful service entry point is:
[HttpPut("exec/command")] public async Task<IActionResult> ExecCommand(string command, params string[] args) { Log.Information($"URL requested: {ControllerContext.HttpContext.Request.GetDisplayUrl()}"); ...... }
client code:
string body;
string restful_path = #"/motors/6";
string cmd = "find";
var request2 = new RestRequest(
resource: $"{restful_path}/exec/command?command={cmd}",
method: Method.PUT);
request2.AddHeader("Content-Type", "application/json");
body = new string\[\] { "abc", "Jeff", "some" };
request2.AddParameter("application/json", body, ParameterType.);
var response = restClient.Execute(request2);
Above code snippet (I referred sample code on the web) can invoke restful service -- ExecCommand() successfully when I install RestSharp 108.xx. But our team project still use RestSharp 106.11.4, Same code can NOT invoke that service.(server is always running, not version difference issue).
Have some experts guide to invoke this service with RestSharp on version 106.11.4
I tried same code on different RestSharp versions, result is different. But I have found sample code for version 106.11.4.

Related

AWS API Gateway - Call GET Method with C# SDK

I have an API Gateway that uses IAM authorization. I have a C# application that I'm hoping to call the API with. I started with a GetMethodRequest but I don't see anyway to set the PathPart parameter.
var userId = _remoteCredentials.UserId;
var key = _remoteCredentials.Key;
var client = new AmazonAPIGatewayClient(userId, key, Amazon.RegionEndpoint.USEast2);
GetMethodRequest getMethodRequest = new GetMethodRequest();
getMethodRequest.HttpMethod = HttpMethod.Get.ToString();
getMethodRequest.ResourceId = "4abcde";
getMethodRequest.RestApiId = "aasfasdfs";
var task = Task.Run(async () => await client.GetMethodAsync(getMethodRequest).ConfigureAwait(false));
I was expecting something like the Test-AGInvokeMethod in the Powershell SDK which allows me to set the query string and the path.
$response = Test-AGInvokeMethod
-RestApiId aasfasdfs
-ResourceId 4abcde
-HttpMethod GET
-PathWithQueryString '/etl/upload_url'
Any help is greatly appreciated.
EDIT Below is something of a solution that I ended up using the AWS4RequestSigner is a library that I found on Github
var signer = new AWS4RequestSigner(userId, key);
var destinationUrl = string.Format("https://ad9vxabc123.execute-api.us-east-2.amazonaws.com/dev/etl/summary/latest?tms_id={0}&model_id={1}", _tmsId, _modelId);
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(destinationUrl),
};
var signed = Task.Run(async () => await signer.Sign(request, "execute-api", "us-east-2").ConfigureAwait(false));
var signedResult = signed.Result;
The AmazonAPIGatewayClient is for managing your API Gateway e.g. adding new stages or deleting API keys.
You're looking to invoke a method on your API Gateway, like Test-AGInvokeMethod does.
To invoke your API gateway, you need to call the deployed API endpoint using a HTTP client.
.NET's in-built HttpClient is a good start.

Why is my header data missing from my Azure Function Http Trigger in .Net 5 when calling from HttpClient.GetAsync

I have a client using HttpClient.GetAsync to call into a Azure Function Http Trigger in .Net 5.
When I call the function using PostMan, I get my custom header data.
However, when I try to access my response object (HttpResponseMessage) that is returned from HttpClient.GetAsync, my header data empty.
I have my Content data and my Status Code. But my custom header data are missing.
Any insight would be appreciated since I have looking at this for hours.
Thanks for you help.
Edit: Here is the code where I am making the http call:
public async Task<HttpResponseMessage> GetQuotesAsync(int? pageNo, int? pageSize, string searchText)
{
var requestUri = $"{RequestUri.Quotes}?pageNo={pageNo}&pageSize={pageSize}&searchText={searchText}";
return await _httpClient.GetAsync(requestUri);
}
Edit 8/8/2021: See my comment below. The issue has something to do with using Blazor Wasm Client.
For anyone having problems after following the tips on this page, go back and check the configuration in the host.json file. you need the Access-Control-Expose-Headers set to * or they won't be send even if you add them. Note: I added the "extensions" node below and removed my logging settings for clarity.
host.json (sample file):
{
"version": "2.0",
"extensions": {
"http": {
"customHeaders": {
"Access-Control-Expose-Headers": "*"
}
}
}
}
This is because HttpResponseMessage's Headers property data type is HttpResponseHeaders but HttpResponseData's Headers property data type is HttpHeadersCollection. Since, they are different, HttpResponseHeaders could not bind to HttpHeadersCollection while calling HttpClient.GetAsync(as it returns HttpResponseMessage).
I could not find a way to read HttpHeadersCollection through HttpClient.
As long as your Azure function code is emitting the header value, you should be able to read that in your client code from the Headers collection of HttpResponseMessage. Nothing in your azure function (which is your remote endpoint you are calling) makes it any different. Remember, your client code has no idea how your remote endpoint is implemented. Today it is azure functions, tomorrow it may be a full blown aspnet core web api or a REST endpoint written in Node.js. Your client code does not care. All it cares is whether the Http response it received has your expected header.
Asumming you have an azure function like this where you are adding a header called total-count to the response.
[Function("quotes")]
public static async Task<HttpResponseData> RunAsync(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("Quotes");
logger.LogInformation("C# HTTP trigger function processed a request for Quotes.");
var quotes = new List<Quote>
{
new Quote { Text = "Hello", ViewCount = 100},
new Quote { Text = "Azure Functions", ViewCount = 200}
};
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("total-count", quotes.Count.ToString());
await response.WriteAsJsonAsync(quotes);
return response;
}
Your existing client code should work as long as you read the Headers property.
public static async Task<HttpResponseMessage> GetQuotesAsync()
{
var requestUri = "https://shkr-playground.azurewebsites.net/api/quotes";
return await _httpClient.GetAsync(requestUri);
}
Now your GetQuotesAsync method can be called somewhere else where you will use the return value of it (HttpResponseMessage instance) and read the headers. In the below example, I am reading that value and adding to a string variable. HttpResponseMessage implements IDisposable. So I am using a using construct to implicitly call the Dispose method.
var msg = "Total count from response headers:";
using (var httpResponseMsg = await GetQuotesAsync())
{
if (httpResponseMsg.Headers.TryGetValues("total-count", out var values))
{
msg += values.FirstOrDefault();
}
}
// TODO: use "msg" variable as needed.
The types which Azure function uses for dealing with response headers is more of an implementation concern of azure functions. It has no impact on your client code where you are using HttpClient and HttpResponseMessage. Your client code is simply dealing with standard http call response (response headers and body)
The issue is not with Blazor WASM, rather if that header has been exposed on your API Side. In your azure function, add the following -
Note: Postman will still show the headers even if you don't expose the headers like below. That's because, Postman doesn't care about CORS headers. CORS is just a browser concept and not a strong security mechanism. It allows you to restrict which other web apps may use your backend resources and that's all.
First create a Startup File to inject the HttpContextAccessor
Package Required: Microsoft.Azure.Functions.Extensions
[assembly: FunctionsStartup(typeof(FuncAppName.Startup))]
namespace FuncAppName
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<HttpContextAccessor>();
}
}
}
Next, inject it into your main Function -
using Microsoft.AspNetCore.Http;
namespace FuncAppName
{
public class SomeFunction
{
private readonly HttpContext _httpContext;
public SomeFunction(HttpContextAccessor contextAccessor)
{
_httpContext = contextAccessor.HttpContext;
}
[FunctionName("SomeFunc")]
public override Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, new[] { "post" }, Route = "run")] HttpRequest req)
{
var response = "Some Response"
_httpContext.Response.Headers.Add("my-custom-header", "some-custom-value");
_httpContext.Response.Headers.Add("my-other-header", "some-other-value");
_httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "my-custom-header, my-other-header");
return new OkObjectResult(response)
}
If you want to allow all headers you can use wildcard (I think, not tested) -
_httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "*");
You still need to add your web-app url to the azure platform CORS. You can add * wildcard, more info here - https://iotespresso.com/allowing-all-cross-origin-requests-azure-functions/
to enable CORS for Local Apps during development - https://stackoverflow.com/a/60109518/9276081
Now to access those headers in your Blazor WASM, as an e.g. you can -
protected override async Task OnInitializedAsync()
{
var content = JsonContent.Create(new { query = "" });
using (var client = new HttpClient())
{
var result = await client.PostAsync("https://func-app-name.azurewebsites.net/api/run", content);
var headers = result.Headers.ToList();
}
}

Twilio making call using Dll version 5.3

If we Use the Url as per the Sample Code,it works fine.Here is the Url Used in sample code : ("http://demo.twilio.com/docs/voice.xml")
As per the Old Twilio Dll version 3.4 Were making Use of the twimlet Echo to make call i.e("http://twimlets.com/echo?Twiml=%3CResponse%3E%3CSay%3EHi+there.%3C%2FSay%3E%3C%2FResponse%3E"));
And i want to to create to create Stateless apploication,Without application Hosting in any server.
The twimlet echo Url is working fine in version 3.4 and the same URL is not working in 5.3.
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXX";
const string authToken = "909dajhdusa78798324ndkjsahd";
TwilioClient.Init(accountSid, authToken);
var to = new PhoneNumber("+919000000000");
var from = new PhoneNumber("+919000000000");
var call = CallResource.Create(to,
from,
url: new Uri("http://twimlets.com/echo?Twiml=test")); //Not working
call = CallResource.Create(to,
from,
url: new Uri("http://twimlets.com/echo?Twiml=<Response><Say>testing</Say></Response>"));//Not working
call = CallResource.Create(to,
from,
url: new Uri("http://twimlets.com/echo?Twiml=%3CResponse%3E%3CSay%3EHi+there.%3C%2FSay%3E%3C%2FResponse%3E"));//Not working
Console.WriteLine(call.Sid);

Error while deserializing Azure ServiceBus Queue message sent from node.js (azure sdk)

Here's my scenario:
I'm sending an Azure ServiceBus Queue message from Node.js using the node azure sdk like so:
var message = {
body: JSON.stringify({ foo: 'Bar' })
};
serviceBusService.sendQueueMessage('myQueue', message, function (error) {
if (!error) {
console.log('msessage sent');
}
});
I have a c# worker role that is listening to the Queue:
QueueClient Client = QueueClient.CreateFromConnectionString(connStr, QueueName);
Client.OnMessage((receivedMessage) =>
{
var body = receivedMessage.GetBody<string>();
});
When the GetBody method gets executed, i get the following error:
There was an error deserializing the object of type System.String. The input source is not correctly formatted
After some digging around, i found THIS article that helped me get a solution:
Client.OnMessage((receivedMessage) =>
{
var bodyJson = new StreamReader(receivedMessage.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
var myMessage = JsonConvert.DeserializeObject<MyMessage>(bodyJson);
});
If anyone has faced this issue and found a better solution, please let me know!
Thanks!
To anyone who found this question if they were getting this error from sending the message using Service Bus Explorer (like me).
Make sure you specify the correct message type in the drop down:
Thanks for the update, I was doing the reverse and this helped me. I thought I'd add to your solution for completeness. The DeserializeObject method needs the "MyMessage" class defining. In your original post, your JSON is:
{ foo: 'Bar' }
If we drop that into json2csharp (json2csharp.com) we now have the class required to complete your solution:
public class MyMessage
{
public string foo { get; set; }
}
Of course, the dependency is having Newtonsoft.Json package added to your Visual Studio solution:
Install-Package Newtonsoft.Json -Pre
Using the nuget package: Microsoft.Azure.ServiceBus
The following info is contained inside as as comment:
If a message is only being sent and received using this Microsoft.Azure.ServiceBus
client library, then the below extension methods are not relevant and should not be used.
If this client library will be used to receive messages that were sent using both WindowsAzure.Messaging client library and this (Microsoft.Azure.ServiceBus) library, then the Users need to add a User property Microsoft.Azure.ServiceBus.Message.UserProperties while sending the message. On receiving the message, this property can be examined to determine if the message was from WindowsAzure.Messaging client library and if so use the message.GetBody() extension method to get the actual body associated with the message.
---------------------------------------------- Scenarios to
use the GetBody Extension method: ----------------------------------------------
If message was constructed using the WindowsAzure.Messaging client library as
follows:
var message1 = new BrokeredMessage("contoso"); // Sending a plain string var
message2 = new BrokeredMessage(sampleObject); // Sending an actual customer object
var message3 = new BrokeredMessage(Encoding.UTF8.GetBytes("contoso")); // Sending
a UTF8 encoded byte array object await messageSender.SendAsync(message1); await
messageSender.SendAsync(message2); await messageSender.SendAsync(message3);
Then retrieve the original objects using this client library as follows: (By
default Microsoft.Azure.ServiceBus.InteropExtensions.DataContractBinarySerializer
will be used to deserialize and retrieve the body. If a serializer other than
that was used, pass in the serializer explicitly.)
var message1 = await messageReceiver.ReceiveAsync(); var returnedData1 = message1.GetBody();
var message2 = await messageReceiver.ReceiveAsync(); var returnedData2 = message1.GetBody();
var message3 = await messageReceiver.ReceiveAsync(); var returnedData3Bytes =
message1.GetBody(); Console.WriteLine($"Message3 String: {Encoding.UTF8.GetString(returnedData3Bytes)}");
------------------------------------------------- Scenarios to NOT use the GetBody
Extension method: ------------------------------------------------- If message
was sent using the WindowsAzure.Messaging client library as follows: var message4
= new BrokeredMessage(new MemoryStream(Encoding.UTF8.GetBytes("contoso"))); await
messageSender.SendAsync(message4); Then retrieve the original objects using this
client library as follows: var message4 = await messageReceiver.ReceiveAsync();
string returned = Encoding.UTF8.GetString(message4.Body); // Since message was
sent as Stream, no deserialization required here.
May it help you
With the latest Service Bus client libraries (.NET, JS, Java, Python), you can send message(s) using the JS library like this:
const serviceBusClient = new ServiceBusClient("<connectionstring>");
const sender = serviceBusClient.createSender("<queuename>");
await sender.sendMessages([{
body: {
title: "hello"
}
}]);
Note that .sendMessages takes a list as an input, even if you're just sending one message.
And get the body of the received message using .NET library like this:
await using var client = new ServiceBusClient("<connectionstring>");
ServiceBusReceiver receiver = client.CreateReceiver("<queuename>");
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();
string body = receivedMessage.Body.ToString();
Console.WriteLine(body); //prints {"title":"hello"}

Android -- How to access data in an ASP.NET database via app?

I have a Windows web server already set up with a website (unlimited application pools) and I want to be able to access a database on that server via the Android app I'm developing. How can I do this? Can someone point me to a tutorial or give code example of how this cross-platform (Android/Java to ASP.NET/C#) communication can be done?
(I'm trying to create a leader board or global scoreboard for my Android game on my server.)
Thanks.
Your app should expose a webservice.
There is no native support for .net soap based webservices. But you can use the ksoap android port:
http://code.google.com/p/ksoap2-android/
which allows an android app to consume a .net asmx webservice.
However the deserialisation of complex on the client side involves lot of code writing for every object you want so pass to the client.
I tried it for a project and there were some problems I ran into (either I could get result back to the client but the parameters i passed where always null or the other way - I could pass arguments but the result was null).
Here is an example I posted for getting an int: How to call a .NET Webservice from Android using KSOAP2?
However, from my current knowlege I would suggest using a .asmx webservice that returns a json string and use a java json serialiser to parse the output. The advantages:
Write less code
Faster, since mobile devices don't always have good internet connections and the xml overhead from soap is bigger than json.
Quickstart:
Create a new asmx Webservice in your .net webapp.
Include a reference to System.Web.
Decorate your webservice class with [ScriptService] and your method with [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string HelloAndroid()
{
return "Hello Android";
}
}
(I think you have to add a reference to System.Web.Extension.dll which is available since .net 3.5).
Your webservice will still return XML (so you can use it with a soap client) unless you make a HTTPPost request with content-type "application/json".
use this code to contact the webservice from android:
private JSONObject sendJsonRequest(string host, int port,
String uri, JSONObject param)
throws ClientProtocolException, IOException, JSONException
{
HttpClient httpClient = new DefaultHttpClient();
HttpHost httpHost = new HttpHost(host, port);
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader("Content-Type", "application/json; charset=utf-8");
if (param != null)
{
HttpEntity bodyEntity = new StringEntity(param.toString(), "utf8");
httpPost.setEntity(bodyEntity);
}
HttpResponse response = httpClient.execute(httpHost, httpPost);
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
InputStream instream = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(instream));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
sb.append(line + "\n");
result = sb.toString();
instream.close();
}
httpPost.abort();
return result != null ? new JSONObject(result) : null;
}
if your webservice methods looks like this:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public User GetUser(string name, int age)
{
return new User { Name = name, Age = age; }
}
You can call it this way from android:
public void getUser() {
// if you put a json object to the server
// the properties are automagically mapped to the methods' input parameters
JSONObject param = new JSONObject();
param.put("name", "John Doe");
param.put("age", 47);
JSONObject result = sendJsonRequest("server", 80,
"http://server:80/service1.asmx/GetUser", param);
if (result != null) {
JSONObject user = new JSONObject(result.getString("d"));
// .net webservices always return the result
// wrapped in a parameter named "d"
system.out.println(user.getString("name"));
system.out.println(user.getInt("age").toString());
}
}
Handling server exceptions on the client side:
Add this class to your project:
import org.json.JSONException;
import org.json.JSONObject;
public class JSONExceptionHelper {
private static final String KEY_MESSAGE = "Message";
private static final String KEY_EXCEPTIONTYPE = "ExceptionType";
private static final String KEY_STACKTRACE = "StackTrace";
public static boolean isException(JSONObject json) {
return json == null
? false
: json.has(KEY_MESSAGE) &&
json.has(KEY_EXCEPTIONTYPE) &&
json.has(KEY_STACKTRACE);
}
public static void ThrowJsonException(JSONObject json) throws JSONException {
String message = json.getString(KEY_MESSAGE);
String exceptiontype = json.getString(KEY_EXCEPTIONTYPE);
String stacktrace = json.getString(KEY_STACKTRACE);
StringBuilder sb = new StringBuilder();
sb.append(exceptiontype);
sb.append(": ");
sb.append(message);
sb.append(System.getProperty("line.separator"));
sb.append(stacktrace);
throw new JSONException(sb.toString());
}
}
Now replace the return statement from the sendJSONRequest with:
JSONObject json = result != null ? new JSONObject(result) : null
if (JSONExceptionHelper.isException(json))
JSONExceptionHelper.ThrowJsonException(json);
return json;
Please note: The exception is passed to the client only if connection comes from localhost.
Otherwise you get an http error 500 (or 501? I can't remember). You have to configure your IIS to send error 500 to the client.
Try it out and create a webservice that always throws an exception.
Sounds like a job for Web Services.
Start by creating a Web Service on the Windows web server, you can do this with ASP.NET (or maybe this might be more current).
On the Java side you can call the webservice and use the results that you get back. I think this question may help you get started on this side.
In case you have trouble writing web methods which return array of objects, you may want to refer here:
ksoap android web-service tutorial
Hope it helps.

Categories