So I'm working on a web API that a Roku Channel will interact with to send and receive data. Roku SDK has a built in XML Parser that is easy to use, but the only problem is that Roku will only parse XML wrapped in an <rsp stat="ok"></rsp> element. I don't see how or where to override the XML Output on the web API to wrap it with the <rsp> element.
So my question is, how can I override the XML Formatter and insert <rsp stat="ok"> before the output, and </rsp> after?
If you are ensuring that you will return only XML by removing JSON formatter like this
config.Formatters.Remove(config.Formatters.JsonFormatter);
you can use a message handler to add the envelope blindly for all responses like this.
public class MyHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
string responseBody = "<rsp stat=\"ok\">" +
await response.Content.ReadAsStringAsync() +
"</rsp>";
response.Content = new StringContent(
responseBody, Encoding.UTF8, "application/xml");
return response;
}
}
Related
Using Audit.Net is it possible to create an audit scope for httpClient requests, in a similar way to the MVC.Core or WebAPI.Core Middleware?
I've tried something like this but not having much success, generally it'll timeout the app.
AuditScope scope = null;
try {
using(HttpClient client = new HttpClient) {
scope = await AuditScope.CreateAsync("",() => client)
// code to initialise the Httpclient
}
}
finally {
await scope.DisposeAsync();
}
I think the only option to hook into the HttpClient is to use a custom HttpClientHandler so you can intercept the rest calls.
Just as an example:
public class AuditClientHandler : HttpClientHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var options = new AuditScopeOptions()
{
EventType = $"{request.Method.Method} {request.RequestUri.AbsoluteUri}",
CreationPolicy = EventCreationPolicy.InsertOnStartReplaceOnEnd,
ExtraFields = new
{
request = GetRequestAudit(request)
}
};
using (var scope = AuditScope.Create(options))
{
var response = await base.SendAsync(request, cancellationToken);
scope.SetCustomField("response", GetResponseAudit(response));
return response;
}
}
}
I've used the InsertOnStartReplaceOnEnd creation policy, so the request is saved before it's sent to the server, and the response is added to the event and saved afterwards.
The implementation of GetRequestAudit / GetResponseAudit is up to you, just return an object (that can be serialized) with the information you want to log.
So each time you need to audit an HttpClient instance, you need to pass the handler to its constructor:
var cli = new HttpClient(new AuditClientHandler());
var response = await cli.GetAsync("http://google.com");
Anyway I will evaluate providing a new library (Audit.HttpClient?) with a configurable Handler so the implementation could be cleaner.
Update
You can now use the Audit.HttpClient extension for a cleaner implementation. Take a look at the documentation here
Doing a project in .Net Core 2, using MVC, I'm attempting to incorporate a project from GitHub that generates the XML for an RSS feed. It is TAlex.RSSFeedGenerator.
To generate the actual document, the FeedGenerator's only option is serializing its RSS object to a MemoryStream:
public void Generate(Rss rss, Stream output)
{
XmlSerializer serializer = new XmlSerializer(typeof(Rss));
serializer.Serialize(output, rss);
}
So FeedGenerator has already serialized the RSS content as XML in Stream, and I want to return that content as XML from an MVC Controller ( return Ok(content_here) ).
How can I do this?
As incorporated originally / currently:
var rss = new Rss();
// ...
var RssFeedGenerator = new FeedGenerator();
var output = new MemoryStream();
RssFeedGenerator.Generate(rss, output);
output.Position = 0;
var sreader = new StreamReader(output);
return Ok(sreader.ReadToEnd());
This puts out a string and is seen as a string by the browser. It is not seen as XML or RSS.
The MVC Controller is defined and decorated like so:
[HttpGet()]
[Produces("text/xml")]
public async Task<IActionResult> GetAsync() {...}
So, I need the string that is already an XML document to be recognized as an XML document, not a string. My goal is also to send the contents as a response directly, not save it to a file and then have to redirect the user to that file or have to have Ok() read from the file.
Also, I can't send the MemoryStream directly to Ok(), because I get an error that one can't access a closed stream.
The browser is currently showing this:
<string><?xml version="1.0" encoding="utf-16"?> ... </string>
(Originally, it was properly decoding the HTML entities, so you'd see:
<string><?xml version="1.0" encoding="utf-16"?> ... </string>
but now it's not even doing that.)
Thanks for clarifying.
Please return ContentResult in order to see the RSS XML. You can have "application/xml" or "application/RSS+XML" or "text/xml"
public async Task<IActionResult> GetAsync()
{
string rssFeed = "<?xml >...";
return new ContentResult
{
Content = rssFeed,
ContentType = "application/RSS+xml"
};
}
I am trying to do webservice async so ui can respond and websevice call is done in background, but since i am little inexpirienced with async stuff i need little help.
Here is my code:
Inside my action result i have call to method which have asyinc stuff in it
public ActionResult SavePackage(string ParcelNumber)
{
/////some other stuff
SaveAsync(ParcelNumber);
}
And
then i have async method :
public async Task SaveAsync(string ParcelNumber)
{
await api.RegisterPackage(ParcelNumber);
}
Which calls api:
public async Task RegisterPackage(string ParcelNumber)
{
var rk = "some api http";
HttpWebRequest request = WebRequest.Create(rk) as HttpWebRequest;
request.Headers.Add("cache-control", "no-cache");
request.Method = "POST";
request.ContentType = "application/json";
string data = "{\n \"ParcelNumber\": \"" + ParcelNumber+ "\"}";
byte[] dataStream = Encoding.UTF8.GetBytes(data);
Stream newStream = request.GetRequestStream();
// Send the data.
newStream.Write(dataStream, 0, dataStream.Length);
newStream.Close();
Task<WebResponse> getResponseTask = Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null);
await getResponseTask.ContinueWith(getResponseAntecedent =>
{
WebResponse webResponse = getResponseAntecedent.Result;
using (var reader = new StreamReader(webResponse.GetResponseStream()))
{
string error = reader.ReadToEnd();
//TODO: use JSON.net to parse this string and look at the error message
var myDeserializedObjList3 = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObjectAtt>(error);
var isValid = myDeserializedObjList3.IsValid;
var ModelErrors = myDeserializedObjList3.ModelErrors;
var ValidationErrors = myDeserializedObjList3.ValidationErrors;
}
});
}
My problem is that the above code is still waiting for response to finish (and that can take about 20 second), and i would like if possible when i call the api i could go back to my ui and let ppl do their stuff while api is proccessed in background.
Anybody have any suggestion?
As I describe on my blog, async does not change the HTTP protocol.
First, the best solution to your problem is to not change your ASP.NET action method at all. Instead, have the actual UI application issue the call asynchronously. If your UI app is a .NET app, then it can use async/await; if it's a web app (i.e., JavaScript), then it can use an AJAX call. Another good option is to introduce SignalR, which allows the server to signal when the work is done.
If you really want to run ASP.NET code outside of a request (which is never recommended), then you can use one of the techniques I describe on my blog for ASP.NET fire-and-forget.
I'm trying to write some tests for my Dart server application, and I've been using the HttpClient class (along with the related HttpClientRequest and HttpClientResponse classes to make test requests to the server (note that I'm using these classes because I need the dart:io package for running the server, so I can't also import dart:html). This has been going fairly well so far, and I've been able to write tests to check that the server is returning responses with the correct HTTP Status code. The base of the code I've been using to make these test calls is as follows:
Future<HttpClientResponse> makeServerRequest(String method, Uri uri, [String jsonData]) async {
HttpClient client = new HttpClient();
HttpClientRequest request = await client.openUrl(method, uri);
request.write(jsonData);
return request.close();
}
Now I need to write a test that makes sure that the body of the response, not just the status code, is correct. The problem is that I can't seem to find anything that allows me to actually access the response body in the HttpClient* classes. The closest I've been able to find so far is the HttpClientResponse.contentLength property, but that only tells me how big the response body is, and isn't the actual content.
How do I retrieve the response body from these requests? Or, if you aren't able to, is there some other way I can make the requests on a server side application so I can read the responses?
The HttpClientResponse object is a Stream, so you can just read it with the listen() method:
response.listen((List<int> data) {
//data as bytes
});
You can also use the codecs from dart:convert to parse the data. The following example reads the response contents to a String:
import 'dart:io';
import 'dart:convert';
import 'dart:async';
Future<String> readResponse(HttpClientResponse response) {
final completer = Completer<String>();
final contents = StringBuffer();
response.transform(utf8.decoder).listen((data) {
contents.write(data);
}, onDone: () => completer.complete(contents.toString()));
return completer.future;
}
Low level
Here is the await for version of collecting the response stream. It's a little more compact than using a completer.
Future<String> readResponse(HttpClientResponse response) async {
final contents = StringBuffer();
await for (var data in response.transform(utf8.decoder)) {
contents.write(data);
}
return contents.toString();
}
You should wrap it in a try catch block to handle errors.
High level
Most of the time from the client side you would use the http library instead:
// import 'package:http/http.dart';
Response response = await get(url);
String content = response.body;
See this article for more details.
A short way of getting the body from an HttpClientResponse is:
Future<String> readResponse(HttpClientResponse response) async {
return response.transform(utf8.decoder).join();
}
Is there any reason that the Breeze Web API implementation of the response to any metadata requests returns a string instead of a JSON object?
Sending metadata as text adds a lot of overhead over the network (due " encoding) and on clientside due manual JSON.parse.
I think that your controller can simply return the Metadata as JSON by specifying the contentType header:
i.e.
[HttpGet]
public HttpResponseMessage Metadata()
{
var result = new HttpResponseMessage { Content = new StringContent(_contextProvider.Metadata())};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return result;
}
As of v 1.2.7, the BreezeController attribute now does this automatically.... and thanks for the idea.