I'm trying to create a controller for Spring MVC that will return a JSONP in Badgerfish format. My code currently creates the JSONP correctly using Jackson, but I do not know how to specify Badgerfish format. Assuming that callback is the name of the callback function and summary is my jaxb object, then my code is currently
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(new JSONPObject(callback,summary));
Is there any way to do this using Jackson or I have to use another framework? I have found an approach to generate Badgerfish using RestEasy, but only for JSON.
I actually managed to solve this with Jettison (I did not find a way to do this with Jackson). The required code is
Marshaller marshaller = null;
Writer writer = new StringWriter();
AbstractXMLStreamWriter xmlStreamWriter = new BadgerFishXMLStreamWriter(writer);
try {
marshaller = jaxbContextSummary.createMarshaller();
marshaller.marshal(myObject, xmlStreamWriter);
} catch (JAXBException e) {
logger.error("Could not construct JSONP response", e);
}
Related
I am creating a wcf client on core.
I create a binding.
var binding = new System.ServiceModel.BasicHttpsBinding();
I need to add MessageID, ReplyTo fields to the request for ws-addressing.
How to do it correctly?
I tried to overwrite request - it didn't work.
All examples are mostly on the usual net framework
It seems there is a library microsoft.web.services2, but I do not understand how to use it.
I'm working on the same requirement, I've found the way to modify the header is work with the OperationContextScope and work with OperationContext.Current.OutgoingMessageHeaders and change the properties.
public async Task<getAttorneyResponseStructure> GetAttorneyAsync(GetAttorneyRequestStructure getAttorneyRequestStructure)
{
try
{
using (new OperationContextScope(Client.InnerChannel))
{
//Client Custom Header
getAttorneyRequestStructure.AttorneyHeader = Header;
//Change the properties to ReplyTo/MessageId
OperationContext.Current.OutgoingMessageHeaders.To = new Uri("http://rydwvgsn01.spga.gov.sa/GSBExpress/Legal/MOJAttorneyInquiry/2.0/AttorneyInquiryService.svc");
OperationContext.Current.OutgoingMessageHeaders.Action = "http://tempuri.org/IAttorneyInquiryService/GetAttorney";
return await Client.GetAttorneyAsync(getAttorneyRequestStructure);
}
}
catch (Exception e)
{
throw;
}
}
I'm creating a .NET Core 3.1 web api method to download a pdf for a given filename. This method is shared across teams where their client code is generated using NSwag.
I recently changed produces attribute to Produces("Application/pdf") from json, this change is required so other teams can generate valid client code. However since this change, I haven't been able to download any files from this method. Requests to download documents return with a 406 error (in Postman) and the following error is logged to the server event viewer.
No output formatter was found for content types 'application/pdf, application/pdf' to write the response.
Reverting the produced content-type to 'application/json' does allow documents to be downloaded, but as mentioned, this value is required to be pdf.
Any suggestions would be greatly appreciated.
Method:
[HttpGet("{*filePath}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Produces("Application/pdf")]
public async Task<ActionResult> GetDocument(string fileName) {
RolesRequiredHttpContextExtensions.ValidateAppRole(HttpContext, _RequiredScopes);
var memoryStream = new MemoryStream();
var memoryStream = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true)) {
stream.CopyTo(memoryStream);
}
memoryStream.Seek(offset: 0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "Application/pdf");
}
I just came across the same error and after some investigation I found out that the cause of the exception was indeed in the model binding error. You already wrote about it in your answer, but on closer inspection it became obvious that the reason was not related to binding itself, rather to the response body.
Since you specified [Produces("application/pdf")] the framework assumes this content type is the only possible for this action, but when an exception is thrown, you get application/json containing error description instead.
So to make this work for both "happy path" and exceptions, you could specify multiple response types:
[Produces("application/pdf", "application/json")]
public async Task<ActionResult> GetDocument(string fileName)
{
...
}
I'am using
public asnyc Task<IActionResult> BuildPDF()
{
Stream pdfStream = _pdfService.GetData();
byte[] memoryContent = pdfStream.ToArray();
return File(memoryContent, "application/pdf");
}
and it works. Could you please try?
The issue was caused by renaming the method parameter and not updating [HttpGet("{*filePath}")] to [HttpGet("{*fileName}")]
I had the same error, it is very confusing in some cases.
I got this error after adding new parameter of type int[] to my method forgetting [FromQuery] attribute for it.
After adding [FromQuery] attribute error gone.
Is there a way to add a response header to spring webflux controller endpoint? for example to the following method I have to add a custom header say 'x-my-header'
#GetMapping(value = "/search/{text}")
#ResponseStatus(value = HttpStatus.OK)
public Flux<SearchResult> search(#PathVariable(
value = "text") String text){
return searchService().find(text);
}
In the functional API, this is really easy; the ServerResponse builder has builders for almost everything you need.
With the annotated controllers; you can return an ResponseEntity<Flux<T>> and set the headers:
#GetMapping(value = "/search/{text}")
public ResponseEntity<Flux<SearchResult>> search(#PathVariable(
value = "text") String text) {
Flux<SearchResult> results = searchService().find(text);
return ResponseEntity.ok()
.header("headername", "headervalue")
.body(results);
}
Note that the updated code doesn't need the #ResponseStatus annotation now.
UPDATE:
Apparently the solution above works; unless you have spring-cloud-starter-netflix-hystrix-dashboard dependency. In that case you can use the following code:
#GetMapping(value = "/search/{text}")
public Mono<ResponseEntity<List<SearchResult>>> search(#PathVariable(
value = "text") String text) {
return searchService().find(text)
.collectList()
.map(list -> ResponseEntity.ok()
.header("Header-Name", "headervalue")
.body(list));
}
A couple of things to note:
Outer type should be Mono<ResponseEntity<T>>: There is one response for request. If you declare it to be a Flux, Spring will try to deserialize the ResponseEntity as if it was a POJO.
You need to use an operator to transform the Flux into a Mono: collectList() or single() will do the job for you.
Checked with Spring Boot 2.0.3.RELEASE
I am trying to use FormDataCOllection in Asp.Net core web api project. As per the documentation it is not there in .net core.
How can I still use it? Or What has replaced it?
You can use the Form property of HttpContext.Request which will return an IFormCollection instance.
FormDataCollection is normally type of the information/class/model sent by forms or grid edit or sumbit links. You can simply use the string as input parameter and then using Json, convert it to the class type you've expected.
Here is an example:
public string NewUser(string values)
{
var message = "";
try
{
var newUser = new User_Detail();
JsonConvert.PopulateObject(values, newUser);
db.User_Detail.Add(newUser);
db.SaveChanges();
message = "User cretaed successfully";
}
catch (Exception ex)
{
message = "An error happened in this method.";
}
return JsonConvert.SerializeObject(message);
}
So, PopulateObject converts your input string (values in this example) to the class you've expected, something similar to FormDataCollection you've needed.
Note: JsonConvert is in Newtonsoft.Json namespace
I have two sites: one of them controls the other sending some commands through Web API. The idea is: the action of the controller site sends a command to the other site, gets the response and perform some business rules, without redirecting to the other site.
I have tons of examples explaining how to implement this via jQuery, but I want to make the controller post the data to the other site, instead of the view.
I found an approach at this answer: How to use System.Net.HttpClient to post a complex type?, but I want the answer for an JSON approach.
Can someone post a simple example using JSON showing how to do this?
As I didn't find a brief answer to my question, I'll post the solution I've made.
As the method uses an HttpClient method that requires async statements, the action below was implemented retuning a Task<ActionResult>. Another modification is if you're saving an object in context.
Instead of using:
context.SaveChanges();
You'll have to use:
await context.SaveChangesAsync();
The code below implements an Action from an ASP.NET MVC4 Controller:
[HttpPost]
public async Task<ActionResult> Create(MyModel model)
{
if (ModelState.IsValid)
{
// Logic to save the model.
// I usually reload saved data using something kind of the statement below:
var inserted = context.MyModels
.AsNoTracking()
.Where(m => m.SomeCondition == someVariable)
.SingleOrDefault();
// Send Command.
// APIMyModel is a simple class with public properties.
var apiModel = new APIMyModel();
apiModel.AProperty = inserted.AProperty;
apiModel.AnotherProperty = inserted.AnotherProperty;
DataContractJsonSerializer jsonSer = new DataContractJsonSerializer(typeof(APIMyModel));
// use the serializer to write the object to a MemoryStream
MemoryStream ms = new MemoryStream();
jsonSer.WriteObject(ms, apiModel);
ms.Position = 0;
//use a Stream reader to construct the StringContent (Json)
StreamReader sr = new StreamReader(ms);
// Note if the JSON is simple enough you could ignore the 5 lines above that do the serialization and construct it yourself
// then pass it as the first argument to the StringContent constructor
StringContent theContent = new StringContent(sr.ReadToEnd(), System.Text.Encoding.UTF8, "application/json");
HttpClient aClient = new HttpClient();
Uri theUri = new Uri("http://yoursite/api/TheAPIAction");
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, theContent);
if (aResponse.IsSuccessStatusCode)
{
// Success Logic. Yay!
}
else
{
// show the response status code
String failureMsg = "HTTP Status: " + aResponse.StatusCode.ToString() + " - Reason: " + aResponse.ReasonPhrase;
}
return RedirectToAction("Index");
}
// if Model is not valid, you can put your logic to reload ViewBag properties here.
}