Create WebAPI post from Console to include $type in json data - asp.net-mvc-4

I'm creating objects and posting them to a webapi. Basically I just can't get the darn things to serialize so as to include the $type info in the json. The following is the code I'm attempting to write. Afterwards is the json I would expect.
var cds = new List<CreditDefaultSwaps>()
{
new CreditDefaultSwaps() { ModelNumber = "SP8A1ETA", BrokerSpread = 0},
new CreditDefaultSwaps() { ModelNumber = "SP3A0TU1", BrokerSpread = 0},
new CreditDefaultSwaps() { ModelNumber = "SP4A102V", BrokerSpread = 0}
};
var client = new HttpClient {BaseAddress = new Uri("http://localhost/BloombergWebAPI/api/")};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// set up request object
var oContract = new WebApiDataServiceRequest
{
RequestType = ReferenceDataRequestServiceTypes.ReferenceDataRequest,
SwapType = BloombergWebAPIMarshal.SwapType.CDS,
SecurityList = cds
};
Tried something like this and the var content was formatted as I would expect
however I couldn't post the data using postasjsonasync
//var content = JsonConvert.SerializeObject(oContract, Formatting.Indented,
// new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });
Console.ReadLine();
var response = client.PostAsJsonAsync("bloombergapi/processbloombergrequest", oContract).Result;
The following is the json I'm trying to post. What am I missing in the above code, I'm sure it's something silly.
{
"$type": "BloombergWebAPIMarshal.WebApiDataServiceRequest, BloombergWebAPIMarshal",
"RequestType": 3,
"SwapType": 1,
"SecurityList": [
{
"$type": "BloombergWebAPIMarshal.CreditDefaultSwaps, BloombergWebAPIMarshal",
"ModelNumber": "SP8A1ETA",
"BrokerSpread": 0
},
{
"$type": "BloombergWebAPIMarshal.CreditDefaultSwaps, BloombergWebAPIMarshal",
"ModelNumber": "SP3A0TU1",
"BrokerSpread": 0
},
{
"$type": "BloombergWebAPIMarshal.CreditDefaultSwaps, BloombergWebAPIMarshal",
"ModelNumber": "SP4A102V",
"BrokerSpread": 0
}
]
}

Created another overload Used this call to produce proper request:
var response = client.PostAsJsonAsync("processbloombergrequest", oContract, TypeNameHandling.Objects).Result
This is the new overload
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, string requestUri, T value, TypeNameHandling typeNameHandling)
{
return client.PostAsJsonAsync<T>(requestUri, value, CancellationToken.None, typeNameHandling);
}
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, string requestUri, T value, CancellationToken cancellationToken, TypeNameHandling typeNameHandling)
{
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings = new JsonSerializerSettings()
{
TypeNameHandling = typeNameHandling
}
};
return client.PostAsync<T>(requestUri, value, formatter, cancellationToken);
}

Related

Can I send GraphQL queries with an httpclient in .NET core?

Is it possible to send graphQL queries with the standard httpclient in .NET core?
When I try to send my query with a client.post I get "Expected { or [ as first syntax token."
How can I send GraphQL queries with a httpclient.
Without having to use a library (like GraphQLHttpClient etc..)
Got it:
Just add "query" as a json object. Like this:
{"query" : "query { __schema { queryType { name } mutationType { name } types { name } directives { name } } }"}
In .NET you can use this in an HTTP post (don't forget to string escape the double quotes
private static string myquery = "{ \"query\" : \"query { __schema { queryType { name } mutationType { name } types { name } directives { name } } }\" }";
Here's an example of how to call a GraphQL endpoint with HttpClient in .net Core:
public async Task<string> GetProductsData(string userId, string authToken)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(_apiUrl)
};
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
var queryObject = new
{
query = #"query Products {
products {
id
description
title
}
}",
variables = new { where = new { userId = userId } }//you can add your where cluase here.
};
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = new StringContent(JsonConvert.SerializeObject(queryObject), Encoding.UTF8, "application/json")
};
using (var response = await httpClient.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
}

Simple serialize ODataQueryOptions

I'm trying to:
[EnableQuery]
[HttpGet]
[ODataRoute("")]
public IHttpActionResult Get(ODataQueryOptions<UserODataModel> options)
{
var users = _repository.RetrieveOData();
var serialQuery = JsonConvert.SerializeObject(options, jsonOptions);
//save serialQuery somewhere
return Ok(users);
}
But got
Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'ReadTimeout' on 'Microsoft.Owin.Host.SystemWeb.CallStreams.InputStream'.'
"Timeouts are not supported on this stream."
I know there is already a question about serialize Stream:
Newtonsoft Json.net - how to serialize content of a stream?
But in this case i can't "extract stream value" from ODataQueryOptions, or can I?
Some ideia?
Since we work on the same company, if anyone is interested, we found a way, maybe not the pretty way, to serialize an ODataQueryOptions:
public static ODataQueryOptions DeserializeQueryOptions(SerializedQueryOptions options)
{
var uri = new Uri(teste.OriginalUri);
var model = ODataConfig.Model; //GetEdmModel
var segment = model.EntityContainer.FindEntitySet(options.EdmType);
var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
var httpConfiguration = new HttpConfiguration();
httpConfiguration.EnableDependencyInjection();
var request = new HttpRequestMessage(HttpMethod.Get, uri)
{
Properties =
{
{ HttpPropertyKeys.HttpConfigurationKey, httpConfiguration },
}
};
var context = new ODataQueryContext(model, options.EntityType, newPath);
var oDataQueryOptions = new ODataQueryOptions(context, request);
return oDataQueryOptions;
}
public static SerializedQueryOptions SerializeQueryOptions(ODataQueryOptions options)
{
return new SerializedQueryOptions
{
OriginalUri = options.Request.RequestUri.AbsoluteUri,
EdmType = options.Context.NavigationSource.Name,
EntityType = options.Context.ElementClrType
};
}
After you serialize it to an object you can serialize it to a JSON string:
var queryOptionsSerialized = new SerializedQueryOptions()
{
OriginalUri = "http://localhost:25723/odata/users?$skip=0&$top=2&$orderby=fullName&$count=true",
EdmType = "users",
EntityType = typeof(UserODataModel)
};
var json = JsonConvert.SerializeObject(queryOptionsSerialized);
var deserialized = JsonConvert.DeserializeObject<SerializedQueryOptions>(json);
var options = ODataQueryOptionsHelper.DeserializeQueryOptions(deserialized);
In case One is not using OData routing or using an ApiController (not ODataController),
modify the way of Obtaining ODataPath to:
ODataUriParser parser = new ODataUriParser(model, serviceRoot, requestUri);
ODataPath path = parser.ParsePath();
//var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
Microsoft.AspNet.OData.Routing.ODataPath newPath = new Microsoft.AspNet.OData.Routing.ODataPath(path.FirstOrDefault());
where the serviceRoot is the Url part other that the path defined in the model.

How to solve this circular dependency problem?

I have two interfaces for components that each requires functionality from the other one. One that generates Oauth tokens, and another one that gets secrets from a secret provider (Azure Key Vault).
The problem is that the Token Provider needs to obtain a secret value (a password) to make its HTTP call, and the Secret Provider class needs to get a Token in order to call Azure. Chicken and Egg problem.
From the other questions I've read, one suggestion is to create a third class/interface on which the original 2 depend, but I'm not sure how that would work here.
Any help and suggestions would be appreciated. Code for all relevant classes/interfaces is shown below.
public interface ISecretProvider
{
string GetSecret(string secretName);
}
public interface ITokenProvider
{
string GetKeyVaultToken();
}
public class OktaTokenProvider : ITokenProvider
{
ISecretProvider _secretProvider;
public string GetKeyVaultToken()
{
var tokenUrl = ConfigurationManager.AppSettings["KeyVault.Token.Url"];
var clientId = ConfigurationManager.AppSettings["KeyVault.Token.ClientId"];
var clientSecret = _secretProvider.GetSecret("ClientSecret");
var scope = ConfigurationManager.AppSettings["KeyVault.Scope"];
var token = GetToken(tokenUrl, clientId, clientSecret, scope);
return token;
}
private string GetToken(string tokenUrl, string clientId, string clientSecret, string scope)
{
var clientCredentials = $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"))}";
string responseFromServer = string.Empty;
bool success = false;
int retryCount = 0;
while (!success)
{
try
{
var tokenWebRequest = (HttpWebRequest)WebRequest.Create(tokenUrl);
tokenWebRequest.Method = "POST";
tokenWebRequest.Headers.Add($"Authorization:{clientCredentials}");
tokenWebRequest.Headers.Add("Cache-control:no-cache");
tokenWebRequest.ContentType = "application/x-www-form-urlencoded";
using (var streamWriter = new StreamWriter(tokenWebRequest.GetRequestStream()))
{
streamWriter.Write($"grant_type=client_credentials&scope={scope}");
streamWriter.Flush();
streamWriter.Close();
}
using (WebResponse response = tokenWebRequest.GetResponse())
{
using (var dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
responseFromServer = reader.ReadToEnd();
reader.Close();
}
dataStream.Close();
}
response.Close();
response.Dispose();
}
success = true;
}
catch (Exception)
{
if (retryCount > 3)
{
throw;
}
else
{
retryCount++;
}
}
}
JToken token = JObject.Parse(responseFromServer);
var accessToken = $"Bearer {token.SelectToken("access_token").ToString()}";
return accessToken;
}
}
public class KeyVaultSecretProvider : ISecretProvider
{
ITokenProvider _tokenProvider;
public KeyVaultSecretProvider(ITokenProvider tokenProvider)
{
_tokenProvider = tokenProvider;
}
public string GetSecret(string secretName)
{
var KeyVaultUrl = ConfigurationManager.AppSettings[Constants.KEYVAULT_ENDPOINT];
var subscriptionKey = ConfigurationManager.AppSettings[Constants.KEYVAULT_SUBSCRIPTION_KEY];
string responseFromServer = "";
var requestedSecretUrl = $"{KeyVaultUrl}{secretName}";
var secretWebRequest = (HttpWebRequest)WebRequest.Create(requestedSecretUrl);
var accessToken = _tokenProvider.GetKeyVaultToken();
secretWebRequest.Method = "GET";
secretWebRequest.Headers.Add("authorization:" + accessToken);
secretWebRequest.Headers.Add("cache-control:no-cache");
secretWebRequest.Headers.Add("Ocp-Apim-Subscription-Key:" + subscriptionKey);
using (WebResponse response = secretWebRequest.GetResponse())
{
using (var dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
responseFromServer = reader.ReadToEnd();
reader.Close();
}
dataStream.Close();
}
response.Close();
response.Dispose();
}
JToken secret = JObject.Parse(responseFromServer);
var secretValue = secret.SelectToken("Secret").ToString();
return secretValue;
}
}
Have a single class implement both interfaces. The two responsibilities are inter-dependent, so put them together in one class. There is nothing wrong with this.

Passing list of object to Web API using RestSharp Client

I'm trying to send list of objects from MVC to WEBAPI using below methods. API is able to able receive the list from controller but, value of each item in the list is either empty/null on API side.
Can anyone please help me to fix this?
Controller Method:
private List<FCM.Models.Facility> GetFacilityDetails()
{
var url = "http://localhost:64664/";
var facilies = new List<Facility>();
facilies.Add( new Facility{ FCLT_ID = 100, FCLT_NM = "Facility 100" });
facilies.Add( new Facility{ FCLT_ID = 200, FCLT_NM = "Facility 200" });
facilies.Add( new Facility{ FCLT_ID = 300, FCLT_NM = "Facility 300" });
var json = JsonConvert.SerializeObject(facilies);
var _client = new RestClient(url);
var request = new RestRequest("api/facility/details", Method.GET) { RequestFormat = DataFormat.Json };
facilies.ForEach(fclt =>
request.AddParameter("facilites", fclt, ParameterType.GetOrPost));
var response = _client.Execute<List<FCM.Models.Facility>>(request);
if (response.Data == null)
{
throw new Exception(response.ErrorMessage);
}
return response.Data;
}
WebAPI method:
[Route("api/facility/details")]
public IEnumerable<Facility> GetFullAddress([FromUri] IEnumerable<Facility> facilities)
{
return null;
}
Like the comment suggested you maybe want to issue a POST request instead, but if you would like to send an array with a GETrequest you could do it like this (with System.Net.Http.HttpClient):
Add a Format method to you Facility class:
public class Facility
{
public int FCLT_ID { get; set; }
public string FCLT_NM { get; set; }
public string Format(int index)
{
return $"[{index}].FCLT_ID={FCLT_ID}&[{index}].FCLT_NM={FCLT_NM}";
}
}
Define a class which can format the array values:
public class FacilityList : List<Facility>
{
public string Format()
{
var builder = new StringBuilder();
for (var i = 0; i < Count; i++)
{
builder.Append(this[i].Format(i));
if(i != Count -1)
{
builder.Append("&");
}
}
return builder.ToString();
}
}
And then issue the request:
var client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:64664/"),
DefaultRequestHeaders = {Accept = {new MediaTypeWithQualityHeaderValue("application/json")}}
};
var facilities = new FacilityList
{
new Facility {FCLT_ID = 100, FCLT_NM = "Facility 100"},
new Facility {FCLT_ID = 200, FCLT_NM = "Facility 200"},
new Facility {FCLT_ID = 300, FCLT_NM = "Facility 300"}
};
var format = facilities.Format();
var response = client.GetAsync("api/facility/details?" + format).GetAwaiter().GetResult();
var result = JsonConvert.DeserializeObject<IEnumerable<Facility>>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
This will bind to your controller action:
[Route("api/facility/details")]
public IHttpActionResult Get([FromUri] IEnumerable<Facility> facilities)
{
// Do stuff..
return Ok(facilities);
}

How to add a root node to xmloutput?

Hi I am new to MVC4 and I am creating RESTFUL WebAPI using asp.net mvc4.
My api returns an xml string as below:
<ArrayOfFacilities xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Facilities>...</Facilities>
<Facilities>...</Facilities>
</ArrayOfFacilities>
I would like to add a node before the above node that will describe pagination such as
<wstxns1:pager>
<wstxns1:page>11</wstxns1:page>
<wstxns1:total>502</wstxns1:total>
<wstxns1:pageSize>50</wstxns1:pageSize>
<wstxns1:prevPage>http://apps.dhis2.org/dev/api/dataElements?page=10</wstxns1:prevPage>
<wstxns1:pageCount>11</wstxns1:pageCount>
</wstxns1:pager>
Please help,
Thanks
public class AppendPagerHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith(
(task) =>
{
HttpResponseMessage response = task.Result;
var xml = response.Content.ReadAsStringAsync().Result;
var newContents = xml.Substring(0, xml.IndexOf("ma\">")+4)+
#"<pager>
<page>11</page>
<total>502</total>
<pageSize>50</pageSize>
<prevPage>http://apps.dhis2.org/dev/api/dataElements?page=10</prevPage>
<pageCount>11</pageCount>
</pager>" + xml.Substring(xml.IndexOf("ma\">") + 4);
response.Content = new StringContent(newContents);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/xml");
return response;
}
);
}
}
GlobalConfiguration.Configuration.MessageHandlers.Add(new Mvc4WebApi.Controllers.ValuesController.AppendPagerHandler());
public List<Facilities> Get()
{
var list = new List<Facilities>();
list.Add(new Facilities { Name = "A" });
list.Add(new Facilities { Name = "B" });
return list;
}