I'm experimenting with a Xamarin app, which should access a .NET Core REST server.
I ran into this issue when switching to https; I can access the api from Chrome no problem, but if I try so from within my app, I get a System.Net.WebException saying
'Error: TrustFailure (A call to SSPI failed, see inner exception.)'.
I setup my server like this:
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var host = WebHost.CreateDefaultBuilder(args)
.UseUrls("https://*:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
return host as IWebHostBuilder;
}
and in my app, I do something like this:
public bool addUser(User user)
{
var request = WebRequest.Create("https://192.168.1.79:5000/api/users");
request.ContentType = "application/json";
request.Method = "POST";
try
{
var json = JsonConvert.SerializeObject(user);
var data = Encoding.UTF8.GetBytes(json);
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
return response.StatusCode == HttpStatusCode.Created;
}
}
catch(Exception ecx)
{
var what = ecx.Message;
return false;
}
}
Thanks so much for any help!
Related
Im trying to use http post to transfer data from flutter to SAP. I can get data without any problem, but post attempt is failing with code 403 (x-csrf-token invalid)
I had the same problem while working in C# but that was resolved using event handler, that triggers just before save (please see below extract of C# code) but i'm unable to find option in flutter. Please guide..
zZSSALE1SRVEntity.SendingRequest2 += new EventHandler<SendingRequest2EventArgs>(_container_SendingRequest_Enhance);
zZSSALE1SRVEntity.SaveChanges();
private void _container_SendingRequest_Enhance(object sender, SendingRequest2EventArgs e)
{
HttpWebResponse response;
string empty = string.Empty;
string str = string.Empty;
CookieContainer cookieContainer = new CookieContainer();
OdataSsaleDEV.ZZSSALE1_SRV_Entities zZSSALE1SRVEntity = new OdataSsaleDEV.ZZSSALE1_SRV_Entities(app_uri)
{
Credentials = credentials
};
string str1 ;
if (empty == string.Empty)
{
HttpWebRequest credentials = (HttpWebRequest)WebRequest.Create(zZSSALE1SRVEntity.BaseUri);
credentials.Method = "GET";
credentials.Headers.Add("X-CSRF-Token", "Fetch");
credentials.Credentials = zZSSALE1SRVEntity.Credentials;
cookieContainer = new CookieContainer();
credentials.CookieContainer = cookieContainer;
try
{
response = (HttpWebResponse)credentials.GetResponse();
}
catch (WebException webException)
{
MessageBox.Show(webException.Message);
return;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
return;
}
empty = response.Headers.Get("X-CSRF-Token");
str = response.Headers.Get("Set-Cookie");
credentials.Abort();
}
if (empty != string.Empty)
{
e.RequestMessage.SetHeader("x-csrf-token", empty);
foreach (Cookie cooky in cookieContainer.GetCookies(zZSSALE1SRVEntity.BaseUri))
{
str1 = string.Concat(str1, ";", cooky.ToString());
}
e.RequestMessage.SetHeader("Cookie", str1.Substring(1));
}
Issue resolved.
Actually server requires session cookies (MYSAPSSO and SAP_SESSIONID) along with x-csrf-token.
I have created a native app in Azure using App Registration and added required permissions for VSTS Agent
Now, I am able to login using oauth authentication with "ADAL" and able to get the token but when trying to access the web api request it gives Http 403 Response
Here is the code example below
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(vstsCollectionUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-TFS-FedAuthRedirect", "Suppress");
client.DefaultRequestHeaders.Authorization = authHeader;
HttpResponseMessage res = client.GetAsync(webapiURL).Result;
}
Please let me know what i am missing
thanks in advance
Seems it's an authentication issue, Just check the value of authHeader.
You can reference below samples for the authentication with header:
Sample 1- auth-samples here ;
Sample 2 - REST API
Post the auth sample as reference here:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
namespace DeviceProfileSample
{
public class Program
{
//============= Config [Edit these with your settings] =====================
internal const string vstsCollectionUrl = "https://myaccount.visualstudio.com"; //change to the URL of your VSTS account; NOTE: This must use HTTPS
internal const string clientId = "872cd9fa-d31f-45e0-9eab-6e460a02d1f1"; //update this with your Application ID from step 2.6 (do not change this if you have an MSA backed account)
//==========================================================================
internal const string VSTSResourceId = "499b84ac-1321-427f-aa17-267ca6975798"; //Static value to target VSTS. Do not change
public static void Main(string[] args)
{
AuthenticationContext ctx = GetAuthenticationContext(null);
AuthenticationResult result = null;
try
{
DeviceCodeResult codeResult = ctx.AcquireDeviceCodeAsync(VSTSResourceId, clientId).Result;
Console.WriteLine("You need to sign in.");
Console.WriteLine("Message: " + codeResult.Message + "\n");
result = ctx.AcquireTokenByDeviceCodeAsync(codeResult).Result;
var bearerAuthHeader = new AuthenticationHeaderValue("Bearer", result.AccessToken);
ListProjects(bearerAuthHeader);
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong.");
Console.WriteLine("Message: " + ex.Message + "\n");
}
}
private static AuthenticationContext GetAuthenticationContext(string tenant)
{
AuthenticationContext ctx = null;
if (tenant != null)
ctx = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
else
{
ctx = new AuthenticationContext("https://login.windows.net/common");
if (ctx.TokenCache.Count > 0)
{
string homeTenant = ctx.TokenCache.ReadItems().First().TenantId;
ctx = new AuthenticationContext("https://login.microsoftonline.com/" + homeTenant);
}
}
return ctx;
}
private static void ListProjects(AuthenticationHeaderValue authHeader)
{
// use the httpclient
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(vstsCollectionUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("User-Agent", "VstsRestApiSamples");
client.DefaultRequestHeaders.Add("X-TFS-FedAuthRedirect", "Suppress");
client.DefaultRequestHeaders.Authorization = authHeader;
// connect to the REST endpoint
HttpResponseMessage response = client.GetAsync("_apis/projects?stateFilter=All&api-version=2.2").Result;
// check to see if we have a succesfull respond
if (response.IsSuccessStatusCode)
{
Console.WriteLine("\tSuccesful REST call");
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
throw new UnauthorizedAccessException();
}
else
{
Console.WriteLine("{0}:{1}", response.StatusCode, response.ReasonPhrase);
}
}
}
}
}
Aren't you missing what authentication,
string credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", token)));
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(vstsCollectionUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials)
HttpResponseMessage response = client.GetAsync(uri).Result;
response.EnsureSuccessStatusCode();
var responseStream = await response.Content.ReadAsStreamAsync();
}
I hope this helps.
I have a web API project done with .NETCore.
My web API receives a request from another Service A, with the information I have I need to do some conversion on the data and send it to another Service B.
I am expecting that Service B send back some response: like OK or NOK. As the number of codes I can get back from Service B are so much. I would like to know which is the best practices to handle those codes?
As you will see in my code, I get the status code in this way:
var status = (int)response.StatusCode;
And the I have some if to handle this. Looking at my code it looks like a very poor status code Handling but at moment it is the best I can do. I am kindly asking suggestions to improve this.
I am using RestSharp.
Following my code:
[HttpPost]
[Produces("application/json", Type = typeof(MyModel))]
public async Task<IActionResult> Post([FromBody]MyModel myModel)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var response = (RestResponse) await _restHelper.GetResponse("ServiceB:url", myModel);
if (response != null)
{
var status = (int)response.StatusCode;
//2xx status OK
if (status >= 200 && status < 300)
{
return Ok(response.Content);
}
//Catch all status code
return StatusCode(status, response.Content);
}
//If for some reason, I don't get any response from ServiceB
return NotFound("No response from ServiceB");
}
catch (Exception ex)
{
_logger.LogError("POST_ERROR", "ServiceB-relay/Post UNEXPECTED ERROR", ex.Message);
return StatusCode(500, "Server error, not able to process your request");
}
}
and this is my restHelper
public class RestHelper: IRestHelper
{
private readonly IConfigurationRoot _config;
public RestHelper(IConfigurationRoot config)
{
_config = config;
}
public async Task<IRestResponse> GetResponse(string configKey, object dtoObject)
{
//Get the URL from the config.json
var url = _config[configKey];
//Create rest client and rest request
var restClient = new RestClient(url);
var request = new RestRequest {Timeout = 30000, Method = Method.POST};
//Add header
request.AddHeader("Accept", "application/json");
//convert the dto object to json
var jsonObject = JsonConvert.SerializeObject(dtoObject.ToString(), Formatting.Indented);
request.AddParameter("application/json", jsonObject, ParameterType.RequestBody);
var taskCompletion = new TaskCompletionSource<IRestResponse>();
//Execute async
restClient.ExecuteAsync(request, r => taskCompletion.SetResult(r));
//await the task to finish
var response = (RestResponse) await taskCompletion.Task;
return response;
}
Thanks
This is Xamarin app which is accessing the www.geonames.org site. When I run it, it generates a System.Net.WebException "Error: ConnectFailure (Connection refused)". However, if I take the url produced in this method and paste it into a browser on the simulator, it works fine and returns the correct JSON.
public async Task GetWeatherAsync(double longitude, double latitude, string username)
{
var url = string.Format("http://api.geonames.org/findNearByWeatherJSON?lat={0}&lng={1}&username={2}", latitude, longitude, username);
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(url);
try
{
var response = await client.GetAsync(client.BaseAddress);
if (response.IsSuccessStatusCode)
{
var JsonResult = response.Content.ReadAsStringAsync().Result;
var weather = JsonConvert.DeserializeObject<WeatherResult>(JsonResult);
SetValues(weather);
}
else
{
Debug.WriteLine(response.RequestMessage);
}
}
catch (HttpRequestException ex)
{
Debug.WriteLine(ex.Message);
}
catch (System.Net.WebException ex)
{
Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
The solution is to add a HttpClientHandler with the appropriate proxy settings. Instantiate an instance of IWebProxy:
public class WebProxy : IWebProxy
{
public ICredentials Credentials { get; set; }
private readonly Uri _proxyUri;
public WebProxy(string proxyString)
{
_proxyUri = new Uri(proxyString);
}
public WebProxy(Uri proxyUri)
{
_proxyUri = proxyUri;
}
public Uri GetProxy(Uri destination)
{
return _proxyUri;
}
public bool IsBypassed(Uri host)
{
return false;
}
}
Then instantiate the HttpClient with a handler that uses the proxy:
NetworkCredential proxyCreds = new NetworkCredential(
ProxyConfig.Username, ProxyConfig.Password);
WebProxy proxy = new WebProxy(ProxyConfig.Url)
{
Credentials = proxyCreds
};
HttpClientHandler handler = new HttpClientHandler
{
PreAuthenticate = true,
UseDefaultCredentials = false,
Proxy = proxy
};
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(url);
Im trying to start Azure VM programmatically (using management certificate). Im getting this error when trying to process http request: error 401 Unauthorized. (thats not an error that appears when certificate is wrong). Tried other request to the same subscription(list hosted services) - went ok, seems like the problem appears only when im tryin to work with virtual machines. Have no idea what am i doing wrong. Here's the code:
static void Main(string[] args)
{
Certificate = new X509Certificate2(Convert.FromBase64String(base64Cer));
string uriFormat = "https://management.azure.com/subscriptions/{my_sub_id}/resourceGroups/{my_resourse_group}/providers/Microsoft.ClassicCompute/virtualMachines/{my_machine_name}/start?api-version={0}";
Uri uri = new Uri(string.Format(uriFormat, Version));
XDocument responseBody;
HttpWebResponse response = InvokeRequest(uri, "POST", out responseBody);
HttpStatusCode statusCode = statusCode = response.StatusCode;
Console.WriteLine("The status of the operation: {0}\n\n", statusCode.ToString());
Console.WriteLine(responseBody.ToString(SaveOptions.OmitDuplicateNamespaces));
Console.Write("Press any key to continue:");
Console.ReadKey();
}
private static HttpWebResponse InvokeRequest( Uri uri, string method, out XDocument responseBody)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = method;
request.Headers.Add("x-ms-version", Version);
request.ClientCertificates.Add(Certificate);
request.ContentType = "application/json";
request.ContentLength = 0;
responseBody = null;
HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
response = (HttpWebResponse)ex.Response;
}
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
if (response.ContentLength > 0)
{
using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
{
try
{
responseBody = XDocument.Load(reader);
}
catch
{
responseBody = null;
}
}
}
response.Close();
return response;
}
The reason you're getting this error is because you're trying to authenticate/authorize an Azure Resource Manager (ARM) API request with an X509 Certificate. Authorization of ARM API requires Azure AD based authorization token. Please see this link for authenticating/authorizing an ARM API request: https://msdn.microsoft.com/en-us/library/azure/dn790557.aspx.
X509 Certificate based authentication/authorization works only for Classic Service Management API requests.