XMl Response from WEB API solution - c#

I have a Web API solution which is configured to respond results always in JSON format as below
config.Formatters.JsonFormatter.SerializerSettings.Formatting =
Newtonsoft.Json.Formatting.Indented;
But now I have a requirement to respond only one of the API calls with XML Response . But if I add the XML formatter to the system
config.Formatters.XmlFormatter.UseXmlSerializer = true;
then all the API calls get affected.
I have a XML string hardcoded which I want to give as reponse .
How can I solve this problem ?

You have to use the Сonfiguration.Formatters.XmlFormatter at api level. Try below code
public IHttpActionResult ApiMethod()
{
...
return Content(HttpStatusCode.OK, Model, Configuration.Formatters.XmlFormatter);
}

Write the below code in your action:
Class1 c1 = new Class1();//Your Model class
var content = new ObjectContent<Class1>(c1,
GlobalConfiguration.Configuration.Formatters.XmlFormatter);
return new HttpResponseMessage()
{
Content = content
};

Related

Error stringifying an object when calling Custom Action in OData D365 Online

I have created a custom action that takes in an input parameter called paramsInput (string).
I want to send to said action a stringified JSON object so that it may be deserialized inside the action.
Snippet of action code:
public void Execute(IServiceProvider serviceProvider)
{
try
{
_context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
_crmService = factory.CreateOrganizationService(_context.UserId);
string paramsInput = _context.InputParameters.Contains("paramsInput") ? _context.InputParameters["paramsInput"].ToString() : string.Empty;
if (paramsInput != string.Empty)
{
// Deserialize to concrete class
InputParams inputParameters = JsonConvert.DeserializeObject<InputParams>(paramsInput);
// logic here...
}
}
catch (Exception ex)
{
// handle exception...
}
}
I have also created a generic function that receives the action's name and the parameters to send and calls the action via OData:
public bool CallMessage(string action, JObject parameters, out string reason)
{
RegenerateAccess(); // Microsoft Online
string urlAPI = "/api/data/v9.1/" + action;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(_serviceUrl);
client.Timeout = new TimeSpan(0, 2, 0); //2 minutes
client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
client.DefaultRequestHeaders.Add("OData-Version", "4.0");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, urlAPI);
/*StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
using (JsonTextWriter writer = new JsonTextWriter(sw))
{
writer.QuoteChar = '\'';
JsonSerializer ser = new JsonSerializer();
ser.Serialize(writer, parameters);
}*/
var jsonObj = JsonConvert.SerializeObject(parameters);
//request.Content = new StringContent(sb.ToString(), Encoding.UTF8, "application/json");
request.Content = new StringContent(jsonObj, Encoding.UTF8, "application/json");
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
//Set the access token
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _authResult.AccessToken);
HttpResponseMessage response = client.SendAsync(request).Result;
reason = response.Content.ReadAsStringAsync().Result;
return response.IsSuccessStatusCode;
}
}
My issue is that I'm getting a Bad Request 400 back, and the response reads - Microsoft.OData.ODataException: An unexpected 'StartObject' node was found for property named 'paramsInput' when reading from the JSON reader. A 'PrimitiveValue' node was expected.
My parameters JObject is structured as follows:
{
"paramsInput" : {
"id" : "xxxx-xxxx...", // some guid
"code" : 1 // int
}
}
or via code:
Guid guid = Guid.NewGuid();
JObject parameters = new JObject();
parameters.Add("id", guid);
parameters.Add("code", 1);
JObject wrapper = new JObject();
wrapper.Add("paramsInput", parameters);
// send wrapper JObject to CallMessage
I don't want to change the structure of CallMessage function as it is a generic function that may be used multiple times by other sources.
The action's parameter paramsInput (containing the JSON) is a string parameter. Therefore, when this parameter is constructed, it must be stringified and your last code snippet would need to look like this:
Guid guid = Guid.NewGuid();
JObject parameters = new JObject();
parameters.Add("id", guid);
parameters.Add("code", 1);
JObject wrapper = new JObject();
wrapper.Add("paramsInput", JsonConvert.SerializeObject(parameters));
// send wrapper JObject to CallMessage
A few side notes:
you decided to create your code executing Dataverse actions from scratch using HttpClient, which in itself is fine, but doing so you need to do all plumbing yourself. Another option would be to use the OrganizationRequest from the MS SDK libraries.
The Action is a bit of legacy nowadays and has been replaced by the Custom API. A Custom API pretty much works in the same way and as a bonus you do not need to create custom plugin steps.
Henk's answer is correct, You told the API to accept a string, thus you must send it the serialized version of your JSON in the string parameter.
I cannot add a comment to Henk's answer due to length restrictions, but I wanted to add a point of clarification here:
The Action is a bit of legacy nowadays and has been replaced by the Custom API. A Custom API pretty much works in the same way and as a bonus you do not need to create custom plugin steps.
You don't need to create a plugin supporting it if you're going to process it somewhere else ( Like PowerAutomate). This is technically called an "Event" in the Power Platform. You also don't need to create a plugin to support a custom action.
The fundamental difference is that "Custom Action" was implemented as a Workflow Operation, where "CustomAPI" is not. You gain a bit of perf as the system does not need to invoke the workflow runtime to run your operation.
Originally, 'Custom Action' was intended to be used as a custom workflow implementation (Think the way you use an HTTP trigger for PowerAutomate today.) However, folks quickly realized that you could wire up a Plugin to the SDK message to get it to act like a 'custom api' inside Dataverse.
Carrying that forward, the CustomAPI Definition is used for both Events and Custom Operations.
As Henk Said, 'Custom Action' is the older process for creating a callable interface for this.

How to create a request for a ASP.net web api

I need guidance on how I can create a POST request to a web API exposed #http://server:8100/api/SoftwareProductBuild' this API takes an XML as input, let's assume the XML is in variable XMLcontent
I have done this python as follows, how to convert to C#?
import requests
with open("PRE_COMMIT_LA.UM.5.8_524f7fef-5b37-11e7-b4ee-f0921c133f10.xml") as f:
body = f.read()
headers = {'Content-Type': 'application/xml'}
response = requests.post(
'http://ctdsapi1:8100/api/SoftwareProductBuild', data=body, headers=headers)
print "Printing DEV Pool Response\n"
print response
print "Done...Printing Dev Pool Response\n"
print response.ok
print response.content
Something like the following should get you most of the way there. Most applicable is the PostAsXmlAsync method.
// In whatever async method
// Assuming actual file? Add applicable checks as well.
var xml = File.ReadAllText(fullPath + "PRE_COMMIT_LA.UM.5.8_524f7fef-5b37-11e7-b4ee-f0921c133f10.xml");
using (var client = new System.Net.Http.HttpClient())
{
var response = await client.PostAsXmlAsync("http://ctdsapi1:8100/api/SoftwareProductBuild", xml);
if (!response.IsSuccessStatusCode)
{
throw new InvalidUriException("Some error with details."));
}
Console.WriteLine("Printing DEV Pool Response\n");
...etc.
}

How to consume Json string from external API? Json returns with escaped or extra characters.

I spent some time trying to figure this one out so I decided to post it here - hopefully it saves some time to someone else.
I'm building an ASP.Net Core Web API MVC application that accepts a Get request and makes a call to an external API (in this case is the Bing Image Search). When returning a result, it would give me a escaped Json string. Example:
"{\"_type\": \"Images\", \"instrumentation\": {\"pageLoadPingUrl\": \"https:...}
Instead of:
{
"_type": "Images",
"instrumentation": {
"pageLoadPingUrl": "https:....
}
Then, I wanted to pass it back to my web client with all sort of non-successes.
I will post shortly how I solved it.
Cheers!
So the issue was that I was trying to process the reponse content the wrong way. All I had to do is user the JsonConvert library.
My full API method looks like this:
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "Enter your key here");
var uri = new Uri("uri to external API here + any parameters");
var response = await client.GetStringAsync(uri);
var jsonResponse = JsonConvert.DeserializeObject(response);
return Ok(jsonResponse);
}
}
Cheers! :)

Content of HttpResponseMessage as JSON

I have an ASP.NET MVC WEB API. For several reasons (redirect because of no authorizations ..), I can't just use a simple object and return it in my controller method. Therefore I need the HttpResponseMessage class which allows me to redirect.
Currently I'm doing this:
var response = new Response { responseCode = Response.ResponseCodes.ItemNotFound };
var formatter = new JsonMediaTypeFormatter();
response.Content = new ObjectContent<Response>(response, formatter, "application/json");
.. to get the object, serialized as JSON, into the content of HttpResponseMessage. Somehow, I have the feeling that there is another, better, way to do this. Any ideas on that?
You can do:
var response = new Response { responseCode = Response.ResponseCodes.ItemNotFound };
Request.CreateResponse<Response>(HttpStatusCode.OK, response);
By default, Web API will set the format of the response based on the Content-Type specified in the HTTP request header but there are some overloads on the CreateResponse method where you can specify the type formatter.
You can also remove the Web API XML serializer to force all responses to be JSON if that's what you want - off the top of my head I think it's a Formatters.Remove method on HttpConfiguration.

Using A Web API for Business Logic?

My web application needs to be able to go and get all my projects from Paymo http://api.paymo.biz/
I am familiar with JSON and XML, but what I'm wondering is, how does one interact with the api (make calls to it).
I would ideally like to make a class in ASP .Net such as PaymoManager(int apikey....)
From there I can wrap the functionality I need. I just need to understand, how do I call functions of the API and how do I get the response. I am not familar with web apis.
Edit: Could you give me an example of this, even with some abstract url. I need this done server side in a CS file.
Basically a simple example that calls someurl.com/somerequest and then how do you receive the JSON or XML... how does this work in terms of a class. I want this in a class.
http://api.paymo.biz/docs/misc.overview.html
To perform an action using the Paymo API, you need to send a request
to the Paymo webservice specifying a method and some arguments, and
will receive a formatted response.
This means that you can use WebClient to download a string from a url:
WebClient client = new WebClient();
string reply = client.DownloadString (address);
Depending on the format you specify, you can parse the reply as XML or JSON.
XDocument xml = XDocument.Parse(reply);
// where ReplyType is a class that defines public
// properties matching the format of the json string
JavaScriptSerializer serializer = new JavaScriptSerializer();
ReplyType abc = serializer.Deserialize<ReplyType>(reply);
If you are using .NET 4.5, you might consider using HttpClient like so:
static async void Main()
{
try
{
// Create a New HttpClient object.
HttpClient client = new HttpClient();
// fill in the details in the following string with your own KEY & TOKEN:
string requestUrl = "https://api.paymo.biz/service/paymo.auth.logout?api_key=API_KEY&format=JSON&auth_token=AUTH_TOKEN"
HttpResponseMessage response = await client.GetAsync(requestUrl );
response.EnsureSuccessStatusCode();
string responseBodyJSON = await response.Content.ReadAsStringAsync();
// Above three lines can be replaced with new helper method in following line
// string body = await client.GetStringAsync(uri);
Console.WriteLine(responseBodyJSON );
// Now you can start parsing your JSON....
}
catch(HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ",e.Message);
}
}

Categories

Resources