If I have a spring mvc rest controller returning byte[], how would I download to my android app using volley? - spring-mvc

I need to implement a list view containing a thumbnail, and this thumbnail is loaded using volley networkimageview. How would I implement this if my controller looks like this:
#RequestMapping (value="/rest/getphoto/", produces=MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte [] get Image (#RequestParam ("imageId"));
I've found many examples regarding the usage of volley but they are not helping me. Besides, I am using secure connection. Thanks in advance.
EDIT: I'm including controller code in my spring mvc project and the portion of code in my android client requesting an image.
* Spring MVC *
#RequestMapping(value = "/rest/singlephoto/", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte[] base64ImageForAndroid(#RequestParam("photoId") String photoIdParam, HttpServletRequest request)
{
String pathToLoad = "/path/default.png";
//HashMap<String, String> retVal = new HashMap<String, String>();
byte[] retVal;
try
{
long photoId = Long.parseLong(photoIdParam);
Photo photo = photoManager.getSinglePhoto(photoId);
if (photo != null)
pathToLoad = photo.getPath();
}
catch (NumberFormatException ex)
{
}
finally
{
try
{
File file = new File(pathToLoad);
retVal = FileUtils.readFileToByteArray(file);
}
catch (IOException ex)
{
retVal = null;
}
}
return retVal;
* Android Client Requesting with volley *
Bitmap thumb = imageCache.get(item.getThumbnailUrl() + "thumb");
if (thumb == null)
{
HttpHeaders headers = new HttpHeaders();
HttpBasicAuthentication auth = new HttpBasicAuthentication(this.username, this.password);
headers.setAuthorization(auth);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM));
Listener<byte[]> imageLoadedListener = new Response.Listener<byte[]>() {
#Override
public void onResponse(byte[] photoByteArray) {
Bitmap bitmap = EfficientImageLoading.decodeBitmapFromByteArray(photoByteArray, viewHolder.thumbnail.getWidth(), viewHolder.thumbnail.getHeight());
viewHolder.thumbnail.setImageBitmap(bitmap);
imageCache.put(item.getThumbnailUrl() + "thumb", bitmap);
//Cache full size and recycle
Bitmap fullBmp = EfficientImageLoading.decodeImageFromByteFullSize(photoByteArray);
imageCache.put(item.getThumbnailUrl(), fullBmp);
}
};
ErrorListener errorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
viewHolder.thumbnail.setImageResource(R.drawable.ic_launcher);
}
};
this.singleInstance.addToRequestQueue(new CustomImageRequest(Request.Method.GET, item.getThumbnailUrl(), errorListener, headers, imageLoadedListener));
}
Application server logs show:
GET /app//photo/rest/singlephoto/?photoId=7 HTTP/1.1" 406 1067
That is 406-- forbidden or something like that. Also android's LogCat shows an error like the following: BasicNetwork.PerformRequest: Unexpected response code 406 for https://domain/app/singlephoto?photoId=7
Is there something wrong with my controller or my client or both?

Related

Playing video stream from mp4 file with moov atom at end using libvlcsharp

I want to play video replay from low-end surveillance camera. Replays are saved on the camera in .mp4 format, with moov atom at the end. It's possible to retrieve file via http request using digset authentication. Approximate size of each video file is 20 MB, but download speed is only 3 Mbps, so downloading whole file takes about 60 s. This is to long, so I want to start displaying video before whole file will be downloaded.
Web browsers handles this kind of problem by reading end of file at the begining. I want to achieve same goal using c# and libvlcsharp, so created HttpMediaInput class.
public class HttpMediaInput : MediaInput
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private HttpClientHandler _handler;
private HttpClient _httpClient;
private string _url;
Stream _stream = null;
public HttpMediaInput(string url, string username, string password)
{
_url = url;
_handler = new HttpClientHandler() { Credentials = new NetworkCredential(username, password) };
_httpClient = new HttpClient(_handler);
}
public override bool Open(out ulong size)
{
size = ulong.MaxValue;
try
{
_stream = _httpClient.GetStreamAsync(_url).Result;
base.CanSeek = _stream.CanSeek;
return true;
}
catch (Exception ex)
{
logger.Error(ex, $"Exception occurred during sending stream request to url: {_url}");
return false;
}
}
public unsafe override int Read(IntPtr buf, uint len)
{
try
{
byte[] buffer = new byte[len];
int bytesReaded = _stream.Read(buffer, 0, buffer.Length);
logger.Trace($"Bytes readed: {bytesReaded}");
Span<byte> byteSpan = new Span<byte>(buf.ToPointer(), buffer.Length);
buffer.CopyTo(byteSpan);
return bytesReaded;
}
catch (Exception ex)
{
logger.Error(ex, "Stream read exception");
return -1;
}
}
...
}
It works great for mp4 files that have all necessary metadata stored on the beginning, but no video is displayed in case of my camera.
Assuming that I will be able to download moov atom from mp4 using http range requests, how to provide this data to libvlc? Is it even possible?
I'm developing application using C#, WPF, dotnet framework.
VLC cannot play files from camera because http digest auth with md5 is considered to be deprecated (related issue in VLC repo).
However, I was able to resolve this problem following cube45 suggestions, I implemented range requests.
public override bool Open(out ulong size)
{
size = ulong.MaxValue;
try
{
HttpRequestMessage requestMessage = new HttpRequestMessage { RequestUri = new Uri(_url) };
requestMessage.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue();
requestMessage.Method = HttpMethod.Head;
var response = _httpClient.SendAsync(requestMessage).Result;
size = (ulong)response.Content.Headers.ContentLength;
_fileSize = size;
logger.Trace($"Received content lenght | {size}");
base.CanSeek = true;
return true;
}
catch (Exception ex)
{
logger.Error(ex, $"Exception occurred during sending head request to url: {_url}");
return false;
}
}
public unsafe override int Read(IntPtr buf, uint len)
{
try
{
HttpRequestMessage requestMessage = new HttpRequestMessage { RequestUri = new Uri(_url) };
long startReadPosition = (long)_currentPosition;
long stopReadPosition = (long)_currentPosition + ((long)_numberOfBytesToReadInOneRequest - 1);
if ((ulong)stopReadPosition > _fileSize)
{
stopReadPosition = (long)_fileSize;
}
requestMessage.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(startReadPosition, stopReadPosition);
requestMessage.Method = HttpMethod.Get;
HttpResponseMessage response = _httpClient.SendAsync(requestMessage).Result;
byte[] readedBytes = response.Content.ReadAsByteArrayAsync().Result;
int readedBytesCount = readedBytes.Length;
_currentPosition += (ulong)readedBytesCount;
logger.Trace($"Bytes readed | {readedBytesCount} | startReadPosition {startReadPosition} | stopReadPosition | {stopReadPosition}");
Span<byte> byteSpan = new Span<byte>(buf.ToPointer(), (int)len);
readedBytes.CopyTo(byteSpan);
return readedBytesCount;
}
catch (Exception ex)
{
logger.Error(ex, "Media reading general exception");
return -1;
}
}
public override bool Seek(ulong offset)
{
try
{
logger.Trace($"Seeking media with offset | {offset}");
_currentPosition = offset;
return true;
}
catch (Exception ex)
{
logger.Error(ex, "MediaInput seekeing general error");
return false;
}
}
This solution seams to work, but there are two unresolved problems:
There is about 8s lag between libvlcsharp starts reading stream and video goes live (waiting time in web browser is about 2s).
Some part of video file at the end is not displayed, because the buffer is too short to hold whole file inside. Related thread

Read Asp.Net Core Response body in ActionFilterAttribute

I'm using Asp.Net Core as a Rest Api Service.
I need access to request and response in ActionFilter. Actually, I found the request in OnActionExcecuted but I can't read the response result.
I'm trying to return value as follow:
[HttpGet]
[ProducesResponseType(typeof(ResponseType), (int)HttpStatusCode.OK)]
[Route("[action]")]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
var model = await _responseServices.Get(cancellationToken);
return Ok(model);
}
And in ActionFilter OnExcecuted method as follow:
_request = context.HttpContext.Request.ReadAsString().Result;
_response = context.HttpContext.Response.ReadAsString().Result; //?
I'm trying to get the response in ReadAsString as an Extension method as follow:
public static async Task<string> ReadAsString(this HttpResponse response)
{
var initialBody = response.Body;
var buffer = new byte[Convert.ToInt32(response.ContentLength)];
await response.Body.ReadAsync(buffer, 0, buffer.Length);
var body = Encoding.UTF8.GetString(buffer);
response.Body = initialBody;
return body;
}
But, there is no result!
How I can get the response in OnActionExcecuted?
Thanks, everyone for taking the time to try and help explain
If you're logging for json result/ view result , you don't need to read the whole response stream. Simply serialize the context.Result:
public class MyFilterAttribute : ActionFilterAttribute
{
private ILogger<MyFilterAttribute> logger;
public MyFilterAttribute(ILogger<MyFilterAttribute> logger){
this.logger = logger;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
var result = context.Result;
if (result is JsonResult json)
{
var x = json.Value;
var status = json.StatusCode;
this.logger.LogInformation(JsonConvert.SerializeObject(x));
}
if(result is ViewResult view){
// I think it's better to log ViewData instead of the finally rendered template string
var status = view.StatusCode;
var x = view.ViewData;
var name = view.ViewName;
this.logger.LogInformation(JsonConvert.SerializeObject(x));
}
else{
this.logger.LogInformation("...");
}
}
I know there is already an answer but I want to also add that the problem is the MVC pipeline has not populated the Response.Body when running an ActionFilter so you cannot access it. The Response.Body is populated by the MVC middleware.
If you want to read Response.Body then you need to create your own custom middleware to intercept the call when the Response object has been populated. There are numerous websites that can show you how to do this. One example is here.
As discussed in the other answer, if you want to do it in an ActionFilter you can use the context.Result to access the information.
For logging whole request and response in the ASP.NET Core filter pipeline you can use Result filter attribute
public class LogRequestResponseAttribute : TypeFilterAttribute
{
public LogRequestResponseAttribute() : base(typeof(LogRequestResponseImplementation)) { }
private class LogRequestResponseImplementation : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var requestHeadersText = CommonLoggingTools.SerializeHeaders(context.HttpContext.Request.Headers);
Log.Information("requestHeaders: " + requestHeadersText);
var requestBodyText = await CommonLoggingTools.FormatRequestBody(context.HttpContext.Request);
Log.Information("requestBody: " + requestBodyText);
await next();
var responseHeadersText = CommonLoggingTools.SerializeHeaders(context.HttpContext.Response.Headers);
Log.Information("responseHeaders: " + responseHeadersText);
var responseBodyText = await CommonLoggingTools.FormatResponseBody(context.HttpContext.Response);
Log.Information("responseBody: " + responseBodyText);
}
}
}
In Startup.cs add
app.UseMiddleware<ResponseRewindMiddleware>();
services.AddScoped<LogRequestResponseAttribute>();
Somewhere add static class
public static class CommonLoggingTools
{
public static async Task<string> FormatRequestBody(HttpRequest request)
{
//This line allows us to set the reader for the request back at the beginning of its stream.
request.EnableRewind();
//We now need to read the request stream. First, we create a new byte[] with the same length as the request stream...
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
//...Then we copy the entire request stream into the new buffer.
await request.Body.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
//We convert the byte[] into a string using UTF8 encoding...
var bodyAsText = Encoding.UTF8.GetString(buffer);
//..and finally, assign the read body back to the request body, which is allowed because of EnableRewind()
request.Body.Position = 0;
return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
}
public static async Task<string> FormatResponseBody(HttpResponse response)
{
//We need to read the response stream from the beginning...
response.Body.Seek(0, SeekOrigin.Begin);
//...and copy it into a string
string text = await new StreamReader(response.Body).ReadToEndAsync();
//We need to reset the reader for the response so that the client can read it.
response.Body.Seek(0, SeekOrigin.Begin);
response.Body.Position = 0;
//Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
return $"{response.StatusCode}: {text}";
}
public static string SerializeHeaders(IHeaderDictionary headers)
{
var dict = new Dictionary<string, string>();
foreach (var item in headers.ToList())
{
//if (item.Value != null)
//{
var header = string.Empty;
foreach (var value in item.Value)
{
header += value + " ";
}
// Trim the trailing space and add item to the dictionary
header = header.TrimEnd(" ".ToCharArray());
dict.Add(item.Key, header);
//}
}
return JsonConvert.SerializeObject(dict, Formatting.Indented);
}
}
public class ResponseRewindMiddleware {
private readonly RequestDelegate next;
public ResponseRewindMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task Invoke(HttpContext context) {
Stream originalBody = context.Response.Body;
try {
using (var memStream = new MemoryStream()) {
context.Response.Body = memStream;
await next(context);
//memStream.Position = 0;
//string responseBody = new StreamReader(memStream).ReadToEnd();
memStream.Position = 0;
await memStream.CopyToAsync(originalBody);
}
} finally {
context.Response.Body = originalBody;
}
}
You can also do...
string response = "Hello";
if (result is ObjectResult objectResult)
{
var status = objectResult.StatusCode;
var value = objectResult.Value;
var stringResult = objectResult.ToString();
responce = (JsonConvert.SerializeObject(value));
}
I used this in a .net core app.
Hope it helps.

Spring MVC Rest unable to return JPEG with "could not find acceptable representation error"

I have a spring-boot app acting as a image server. I POST an image to be persisted to mongodb. I then retrieve it, resize and return it.
Here is the project configuration:
#Configuration
public class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
}
And here is the endpoint:
#RequestMapping(value = "images/{filename}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<BufferedImage> getSizedImage(#PathVariable String filename, #RequestParam int width, #RequestParam int height) throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
GridFSDBFile savedFile = mongoFileService.getStore( filename );
if ( savedFile != null ) {
try {
BufferedImage image = ImageIO.read( savedFile.getInputStream() );
image = resize( image, Method.SPEED, width, height, Scalr.OP_ANTIALIAS );
LOGGER.info("Returning Filename " + savedFile.getFilename() + " sized to " + width + " X " + height);
return new ResponseEntity<BufferedImage>(image, headers, HttpStatus.OK);
} catch ( Exception ex ) {
ex.printStackTrace();
LOGGER.error( "Error sizing file " + filename + ": " + ex.getMessage() );
return new ResponseEntity<BufferedImage>(null, headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
} else {
LOGGER.error( "Could not find requested file " + filename );
return new ResponseEntity<BufferedImage>(null, headers, HttpStatus.NOT_FOUND);
}
}
The image is retrieved and resized (I can actually preview when debugging in IntelliJ). But when it is returned, I get the following error:
Controller [org.springframework.boot.autoconfigure.web.BasicErrorController]
Method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:195)
And I see this in the logs:
Method [error] returned [<406 Not Acceptable,{timestamp=Sat Aug 22 11:05:59 MDT 2015, status=406, error=Not Acceptable, exception=org.springframework.web.HttpMediaTypeNotAcceptableException, message=Could not find acceptable representation, path=/images/1440263145562_profile_04132015.PNG},{}>]
2015-08-22 11:05:59.711 DEBUG 2478 --- [0.1-3000-exec-3] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Sat Aug 22 11:05:59 MDT 2015, status=406, error=Not Acceptable, exception=org.springframework.web.HttpMediaTypeNotAcceptableException, message=Could not find acceptable representation, path=/images/1440263145562_profile_04132015.PNG}] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#5bf1ba3a]
2015-08-22 11:05:59.711 DEBUG 2478 --- [0.1-3000-exec-3] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
I have tried with & without the #ResponseBody and it doesn't appear to make a difference either. I have the produces and content type set correctly (I think).
I added these converters (although I thought SpringBoot provided these), but to no avail:
#Configuration
public class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
#Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter(){
ByteArrayHttpMessageConverter bam = new ByteArrayHttpMessageConverter();
List<org.springframework.http.MediaType> mediaTypes = new LinkedList<MediaType>();
mediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON);
mediaTypes.add(org.springframework.http.MediaType.IMAGE_JPEG);
mediaTypes.add(org.springframework.http.MediaType.IMAGE_PNG);
mediaTypes.add(org.springframework.http.MediaType.IMAGE_GIF);
mediaTypes.add(org.springframework.http.MediaType.TEXT_PLAIN);
bam.setSupportedMediaTypes(mediaTypes);
return bam;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter mapper = new MappingJackson2HttpMessageConverter();
converters.add(mapper);
converters.add(byteArrayHttpMessageConverter());
super.configureMessageConverters(converters);
}
}
I hope someone can see what is causing this issue.
Try this piece of code
#RequestMapping("/sparklr/photos/{id}")
public ResponseEntity<BufferedImage> photo(#PathVariable String id) throws Exception {
InputStream photo = sparklrService.loadSparklrPhoto(id);
if (photo == null) {
throw new UnavailableException("The requested photo does not exist");
}
BufferedImage body;
MediaType contentType = MediaType.IMAGE_JPEG;
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
if (imageReaders.hasNext()) {
ImageReader imageReader = imageReaders.next();
ImageReadParam irp = imageReader.getDefaultReadParam();
imageReader.setInput(new MemoryCacheImageInputStream(photo), true);
body = imageReader.read(0, irp);
} else {
throw new HttpMessageNotReadableException("Could not find javax.imageio.ImageReader for Content-Type ["
+ contentType + "]");
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<BufferedImage>(body, headers, HttpStatus.OK);
}
EDIT:
We have to configure MessageConverter
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new BufferedImageHttpMessageConverter());
}
Here I have Content Negotiator like this
#Bean
public ContentNegotiatingViewResolver contentViewResolver() throws Exception {
ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON);
contentViewResolver.setContentNegotiationManager(contentNegotiationManager.getObject());
contentViewResolver.setDefaultViews(Arrays.<View> asList(new MappingJackson2JsonView()));
return contentViewResolver;
}
I think the message inside your logs can clear your doubts. Have a close look at your logs and comment me again
I think the problem is that none of the registered message converters knows how to write a BufferedImage to the response in the format dictated by the accept header. Try registering your own message converter that knows how to write out a BufferedImage in the requested format.

Web API Return OAuth Token as XML

Using the default Visual Studio 2013 Web API project template with individual user accounts, and posting to the /token endpoint with an Accept header of application/xml, the server still returns the response in JSON:
{"access_token":"...","token_type":"bearer","expires_in":1209599}
Is there a way to get the token back as XML?
According to RFC6749 the response format should be JSON and Microsoft implemented it accordingly. I found out that JSON formatting is implemented in Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler internal class with no means of extension.
I also encountered the need to have token response in XML.
The best solution I came up with was to implement HttpModule converting JSON to XML when stated in Accept header.
public class OAuthTokenXmlResponseHttpModule : IHttpModule
{
private static readonly string FilterKey = typeof(OAuthTokenXmlResponseHttpModule).Name + typeof(MemoryStreamFilter).Name;
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationOnBeginRequest;
application.EndRequest += ApplicationOnEndRequest;
}
private static void ApplicationOnBeginRequest(object sender, EventArgs eventArgs)
{
var application = (HttpApplication)sender;
if (ShouldConvertToXml(application.Context.Request) == false) return;
var filter = new MemoryStreamFilter(application.Response.Filter);
application.Response.Filter = filter;
application.Context.Items[FilterKey] = filter;
}
private static bool ShouldConvertToXml(HttpRequest request)
{
var isTokenPath = string.Equals("/token", request.Path, StringComparison.InvariantCultureIgnoreCase);
var header = request.Headers["Accept"];
return isTokenPath && (header == "text/xml" || header == "application/xml");
}
private static void ApplicationOnEndRequest(object sender, EventArgs eventArgs)
{
var context = ((HttpApplication) sender).Context;
var filter = context.Items[FilterKey] as MemoryStreamFilter;
if (filter == null) return;
var jsonResponse = filter.ToString();
var xDocument = JsonConvert.DeserializeXNode(jsonResponse, "oauth");
var xmlResponse = xDocument.ToString(SaveOptions.DisableFormatting);
WriteResponse(context.Response, xmlResponse);
}
private static void WriteResponse(HttpResponse response, string xmlResponse)
{
response.Clear();
response.ContentType = "application/xml;charset=UTF-8";
response.Write(xmlResponse);
}
public void Dispose()
{
}
}
public class MemoryStreamFilter : Stream
{
private readonly Stream _stream;
private readonly MemoryStream _memoryStream = new MemoryStream();
public MemoryStreamFilter(Stream stream)
{
_stream = stream;
}
public override void Flush()
{
_stream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _stream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_memoryStream.Write(buffer, offset, count);
_stream.Write(buffer, offset, count);
}
public override string ToString()
{
return Encoding.UTF8.GetString(_memoryStream.ToArray());
}
#region Rest of the overrides
public override bool CanRead
{
get { throw new NotImplementedException(); }
}
public override bool CanSeek
{
get { throw new NotImplementedException(); }
}
public override bool CanWrite
{
get { throw new NotImplementedException(); }
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#endregion
}
Ok I had such a fun time trying to figure this out using OWIN I thought I would share my solution with the community, I borrowed some insight from other posts https://stackoverflow.com/a/26216511/1148288 and https://stackoverflow.com/a/29105880/1148288 along with the concepts Alexei describs in his post. Nothing fancy doing with implementation but I had a requirement for my STS to return an XML formatted response, I wanted to keep with the paradigm of honoring the Accept header, so my end point would examine that to determine if it needed to run the XML swap or not. This is what I am current using:
private void ConfigureXMLResponseSwap(IAppBuilder app)
{
app.Use(async (context, next) =>
{
if (context.Request != null &&
context.Request.Headers != null &&
context.Request.Headers.ContainsKey("Accept") &&
context.Request.Headers.Get("Accept").Contains("xml"))
{
//Set a reference to the original body stream
using (var stream = context.Response.Body)
{
//New up and set the response body as a memory stream which implements the ability to read and set length
using (var buffer = new MemoryStream())
{
context.Response.Body = buffer;
//Allow other middlewares to process
await next.Invoke();
//On the way out, reset the buffer and read the response body into a string
buffer.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(buffer))
{
string responsebody = await reader.ReadToEndAsync();
//Using our responsebody string, parse out the XML and add a declaration
var xmlVersion = JsonConvert.DeserializeXNode(responsebody, "oauth");
xmlVersion.Declaration = new XDeclaration("1.0", "UTF-8", "yes");
//Convert the XML to a byte array
var bytes = Encoding.UTF8.GetBytes(xmlVersion.Declaration + xmlVersion.ToString());
//Clear the buffer bits and write out our new byte array
buffer.SetLength(0);
buffer.Write(bytes, 0, bytes.Length);
buffer.Seek(0, SeekOrigin.Begin);
//Set the content length to the new buffer length and the type to an xml type
context.Response.ContentLength = buffer.Length;
context.Response.ContentType = "application/xml;charset=UTF-8";
//Copy our memory stream buffer to the output stream for the client application
await buffer.CopyToAsync(stream);
}
}
}
}
else
await next.Invoke();
});
}
Of course you would then wire this up during startup config like so:
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
//Highly recommend this is first...
ConfigureXMLResponseSwap(app);
...more config stuff...
}
Hope that helps any other lost souls that find there way to the this post seeking to do something like this!
take a look here i hope it can help how to set a Web API REST service to always return XML not JSON
Could you retry by doing the following steps:
In the WebApiConfig.Register(), specify
config.Formatters.XmlFormatter.UseXmlSerializer = true;
var supportedMediaTypes = config.Formatters.XmlFormatter.SupportedMediaTypes;
if (supportedMediaTypes.Any(it => it.MediaType.IndexOf("application/xml", StringComparison.InvariantCultureIgnoreCase) >= 0) ==false)
{
supportedMediaTypes.Insert(0,new MediaTypeHeaderValue("application/xml"));
}
I normally just remove the XmlFormatter altogether.
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
Add the line above in your WebApiConfig class...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

How to Pass custom objects using Spring's REST Template

I have a requirement to pass a custom object using RESTTemplate to my REST service.
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<String, Object>();
...
requestMap.add("file1", new FileSystemResource(..);
requestMap.add("Content-Type","text/html");
requestMap.add("accept", "text/html");
requestMap.add("myobject",new CustomObject()); // This is not working
System.out.println("Before Posting Request........");
restTemplate.postForLocation(url, requestMap);//Posting the data.
System.out.println("Request has been executed........");
I'm not able to add my custom object to MultiValueMap. Request generation is getting failed.
Can someone helps me to find a way for this? I can simply pass a string object without problem.User defined objects makes the problem.
Appreciate any help !!!
You can do it fairly simply with Jackson.
Here is what I wrote for a Post of a simple POJO.
#XmlRootElement(name="newobject")
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class NewObject{
private String stuff;
public String getStuff(){
return this.stuff;
}
public void setStuff(String stuff){
this.stuff = stuff;
}
}
....
//make the object
NewObject obj = new NewObject();
obj.setStuff("stuff");
//set your headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//set your entity to send
HttpEntity entity = new HttpEntity(obj,headers);
// send it!
ResponseEntity<String> out = restTemplate.exchange("url", HttpMethod.POST, entity
, String.class);
The link above should tell you how to set it up if needed. Its a pretty good tutorial.
To receive NewObject in RestController
#PostMapping("/create") public ResponseEntity<String> createNewObject(#RequestBody NewObject newObject) { // do your stuff}
you can try this
public int insertParametro(Parametros parametro) throws LlamadasWSBOException {
String metodo = "insertParam";
String URL_WS = URL_WS_BASE + metodo;
Integer request = null;
try {
logger.info("URL_WS: " + URL_WS);
request = restTemplate.postForObject(URL_WS, parametro, Integer.class);
} catch (RestClientResponseException rre) {
logger.error("RestClientResponseException insertParametro [WS BO]: " + rre.getResponseBodyAsString());
logger.error("RestClientResponseException insertParametro [WS BO]: ", rre);
throw new CallWSBOException(rre.getResponseBodyAsString());
} catch (Exception e) {
logger.error("Exception insertParametro[WS BO]: ", e);
throw new CallWSBOException(e.getMessage());
}
return request;
}

Resources