I am trying to use a custom ITempDataProvider provider to store TempData in a browser's cookie instead of session state. However, everything works fine except that I am unable to remove the cookie from the Response stream after reading it.
Any ideas?
Thanks!
public class CookieTempDataProvider : ITempDataProvider
{
internal const string TempDataCookieKey = "__ControllerTempData";
HttpContextBase _httpContext;
public CookieTempDataProvider(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
_httpContext = httpContext;
}
public HttpContextBase HttpContext
{
get
{
return _httpContext;
}
}
protected virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey];
if (cookie != null && !string.IsNullOrEmpty(cookie.Value))
{
IDictionary<string, object> deserializedTempData = DeserializeTempData(cookie.Value);
// Remove cookie
cookie.Expires = DateTime.MinValue;
cookie.Value = string.Empty;
_httpContext.Request.Cookies.Remove(TempDataCookieKey);
if (_httpContext.Response != null && _httpContext.Response.Cookies != null)
{
HttpCookie responseCookie = _httpContext.Response.Cookies[TempDataCookieKey];
if (responseCookie != null)
{
// Remove cookie
cookie.Expires = DateTime.MinValue;
cookie.Value = string.Empty;
_httpContext.Response.Cookies.Remove(TempDataCookieKey);
}
}
return deserializedTempData;
}
return new Dictionary<string, object>();
}
protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
string cookieValue = SerializeToBase64EncodedString(values);
var cookie = new HttpCookie(TempDataCookieKey);
cookie.HttpOnly = true;
cookie.Value = cookieValue;
_httpContext.Response.Cookies.Add(cookie);
}
public static IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData)
{
byte[] bytes = Convert.FromBase64String(base64EncodedSerializedTempData);
var memStream = new MemoryStream(bytes);
var binFormatter = new BinaryFormatter();
return binFormatter.Deserialize(memStream, null) as IDictionary<string, object> /*TempDataDictionary : This returns NULL*/;
}
public static string SerializeToBase64EncodedString(IDictionary<string, object> values)
{
MemoryStream memStream = new MemoryStream();
memStream.Seek(0, SeekOrigin.Begin);
var binFormatter = new BinaryFormatter();
binFormatter.Serialize(memStream, values);
memStream.Seek(0, SeekOrigin.Begin);
byte[] bytes = memStream.ToArray();
return Convert.ToBase64String(bytes);
}
IDictionary<string, object> ITempDataProvider.LoadTempData(ControllerContext controllerContext)
{
return LoadTempData(controllerContext);
}
void ITempDataProvider.SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
SaveTempData(controllerContext, values);
}
}
There is a better solution by Brock Allen on GitHub that uses encryption, 2 forms of serialization, and compression to protect and optimize the cookies.
https://github.com/brockallen/CookieTempData
Here is a link to the blog about it:
http://brockallen.com/2012/06/11/cookie-based-tempdata-provider/
He also has a good technique using IControllerFactory to ensure every controller is supplied with an instance of ITempDataProvider.
Hi I too had the same issue and it was an issue with the implementation of CookieTempDataProvider.
So I modified the code a bit and now it works perfectly.
When it reads the data from the cookie, it removes it from both the request and response. But add another cookie with an empty value in the SaveData function which is called when the request processing is completed.
Points to note : If you want to remove a cookie, you have to set the timeout value and send it back to the client and then the browser will remove it. We cannot do it otherwise from the code a the cookie is handled by the browser
And I found out that setting the expiration to DateTime.MinValue does not expire the cookie in chrome (don't know about the other browsers) so I set it to 2001-01-01 :)
Here is the working code
public class CookieTempDataProvider : ITempDataProvider
{
internal const string TempDataCookieKey = "__ControllerTempData";
HttpContextBase _httpContext;
public CookieTempDataProvider(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
_httpContext = httpContext;
}
public HttpContextBase HttpContext
{
get
{
return _httpContext;
}
}
protected virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
if (_httpContext.Request.Cookies.AllKeys.Contains(TempDataCookieKey)) //we need this because
//Cookies[TempDataCookieKey] will create the cookie if it does not exist
{
HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey];
if (cookie != null && !string.IsNullOrEmpty(cookie.Value))
{
IDictionary<string, object> deserializedTempData = DeserializeTempData(cookie.Value);
// Remove cookie
cookie.Expires = new DateTime(2000, 1, 1);
cookie.Value = string.Empty;
_httpContext.Request.Cookies.Remove(TempDataCookieKey);
if (_httpContext.Response != null && _httpContext.Response.Cookies != null)
{
HttpCookie responseCookie = _httpContext.Response.Cookies[TempDataCookieKey];
if (responseCookie != null)
{
// Remove cookie
cookie.Expires = new DateTime(2000, 1, 1);
cookie.Value = string.Empty;
_httpContext.Response.Cookies.Remove(TempDataCookieKey);
}
}
return deserializedTempData;
}
}
return new Dictionary<string, object>();
}
protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
if (values != null && values.Count > 0)
{
//there are values to set, so add the cookie. But no need to expire it as we need the browser to send the
//cookie back with the next request
string cookieValue = SerializeToBase64EncodedString(values);
var cookie = new HttpCookie(TempDataCookieKey);
cookie.HttpOnly = true;
cookie.Value = cookieValue;
_httpContext.Response.Cookies.Add(cookie);
}
else
{
//Still we need to add the cookie with the expiration set, to make the client browser remove the cookie from the request.
//Otherwise the browser will continue to send the cookie with the response
//Also we need to do this only if the requet had a tempdata cookie
if (_httpContext.Request.Cookies.AllKeys.Contains(TempDataCookieKey))
{
{
HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey];
// Remove the request cookie
cookie.Expires = new DateTime(2000, 1, 1);
cookie.Value = string.Empty;
_httpContext.Request.Cookies.Remove(TempDataCookieKey);
var rescookie = new HttpCookie(TempDataCookieKey);
rescookie.HttpOnly = true;
rescookie.Value = "";
rescookie.Expires = new DateTime(2000, 1, 1); //so that the browser will remove the cookie when it receives the request
_httpContext.Response.Cookies.Add(rescookie);
}
}
}
}
public static IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData)
{
byte[] bytes = Convert.FromBase64String(base64EncodedSerializedTempData);
var memStream = new MemoryStream(bytes);
var binFormatter = new BinaryFormatter();
return binFormatter.Deserialize(memStream, null) as IDictionary<string, object> /*TempDataDictionary : This returns NULL*/;
}
public static string SerializeToBase64EncodedString(IDictionary<string, object> values)
{
MemoryStream memStream = new MemoryStream();
memStream.Seek(0, SeekOrigin.Begin);
var binFormatter = new BinaryFormatter();
binFormatter.Serialize(memStream, values);
memStream.Seek(0, SeekOrigin.Begin);
byte[] bytes = memStream.ToArray();
return Convert.ToBase64String(bytes);
}
IDictionary<string, object> ITempDataProvider.LoadTempData(ControllerContext controllerContext)
{
return LoadTempData(controllerContext);
}
void ITempDataProvider.SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
SaveTempData(controllerContext, values);
}
}
Here is an example of a working solution without lots of excess code. It uses Json.NET for serializing, which is faster than BinaryFormatter + Base64Encoding and also produces a much shorter string (=less http overhead).
public class CookieTempDataProvider : ITempDataProvider
{
const string cookieKey = "temp";
public IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
var cookie = controllerContext.HttpContext.Request.Cookies[cookieKey];
if (cookie != null) {
return JsonConvert.DeserializeObject<IDictionary<string, object>>(cookie.Value);
}
return null;
}
// Method is called after action execution. The dictionary mirrors the contents of TempData.
// If there are any values in the dictionary, save it in a cookie. If the dictionary is empty,
// remove the cookie if it exists.
public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
var ctx = controllerContext.HttpContext;
if (values.Count > 0) {
var cookie = new HttpCookie(cookieKey)
{
HttpOnly = true,
Value = JsonConvert.SerializeObject(values)
};
ctx.Response.Cookies.Add(cookie);
} else if (ctx.Request.Cookies[cookieKey] != null) {
// Expire cookie to remove it from browser.
ctx.Response.Cookies[cookieKey].Expires = DateTime.Today.AddDays(-1);
}
}
}
Related
I have made a REST call to a url and need to pass the jsonresponse obtained from the synchronous method to the below asynchronous method.I have used a static variable - strresponse to do the same.But i am getting a null value when i call this value in the asynchronous method.Could this be because asynchronous methods do not remember the value given by a synchronous method? is there any alternate way this could be done?
code below:
public with sharing class myController {
public Static String strResponse ;
#AuraEnabled
public static Map<String, Object> retriveNews(){
HttpRequest httpRequest = new HttpRequest();
httpRequest.setEndpoint('endpoint URL');
httpRequest.setMethod('GET');
try{
Http http = new Http();
HttpResponse httpResponse = http.send(httpRequest);
if(httpResponse.getStatusCode() == 200){
newsController.strResponse = httpResponse.getBody();
} else {
throw new CalloutException(httpResponse.getBody());
}
} catch(Exception ex){
throw ex;
}
Map<String, Object> newsJsonData = new Map<String, Object>();
if(!String.isBlank(newsController.strResponse)){
System.debug('jsonstring:'+newsController.strResponse);
newsJsonData = (Map<String, Object>)JSON.deserializeUntyped(newsController.strResponse);
}
System.debug('jsonstring in retrivenews:'+newsController.strResponse);
if(!newsJsonData.isEmpty()){
return newsJsonData;
} else {
return null;
}
}
#future(callout=true)
public static void insertnews()
{
List<Newsroom__c> nrmlist = new List<Newsroom__c>();
System.debug('jsonstring in insertnews:'+newsController.strResponse);
JSONParser parser = JSON.createParser(newsController.strResponse);
while (parser.nextToken() != null) {
// Start at the array of invoices.
if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
while (parser.nextToken() != null) {
// Advance to the start object marker to
// find next invoice statement object.
if (parser.getCurrentToken() == JSONToken.START_OBJECT) {
objectne nrm = (objectne)parser.readValueAs(objectne.class);
objectne__c nroom = new objectne__c(Author__c = nrm.Author,Description__c = nrm.Description);
String s = JSON.serialize(nrm);
system.debug('Serialized object: ' + s);
nrmlist.add(nroom);
system.debug('list of nrooms:'+ nrmlist);
}
}
}
}
Database.SaveResult[] lsr = Database.insert(nrmlist, false) ;
System.debug(lsr);
}
Error - when newscontroller.insertnews() is called - null string to parser
Using OSMSharp I am having trouble to open a stream for a file (which I can provide on demand)
The error occurs in PBFReader (line 104)
using (var tmp = new LimitedStream(_stream, length))
{
header = _runtimeTypeModel.Deserialize(tmp, null, _blockHeaderType) as BlobHeader;
}
and states: "ProtoBuf.ProtoException: 'Invalid field in source data: 0'" which might mean different things as I have read in this SO question.
The file opens and is visualized with QGis so is not corrupt in my opinion.
Can it be that the contracts do not match? Is OsmSharp/core updated to the latest .proto files for OSM from here (although not sure if this is the real original source for the definition files).
And what might make more sense, can it be that the file I attached is generated for v2 of OSM PBF specification?
In the code at the line of the exception I see the following comment which makes me wonder:
// TODO: remove some of the v1 specific code.
// TODO: this means also to use the built-in capped streams.
// code borrowed from: http://stackoverflow.com/questions/4663298/protobuf-net-deserialize-open-street-maps
// I'm just being lazy and re-using something "close enough" here
// note that v2 has a big-endian option, but Fixed32 assumes little-endian - we
// actually need the other way around (network byte order):
// length = IntLittleEndianToBigEndian((uint)length);
BlobHeader header;
// again, v2 has capped-streams built in, but I'm deliberately
// limiting myself to v1 features
So this makes me wonder if OSM Sharp is (still) up-to-date.
My sandbox code looks like this:
using OsmSharp.Streams;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OsmSharp.Tags;
namespace OsmSharp
{
class Program
{
private const string Path = #"C:\Users\Bernoulli IT\Documents\Applications\Argaleo\Test\";
private const string FileNameAntarctica = "antarctica-latest.osm";
private const string FileNameOSPbf = "OSPbf";
private const Boolean useRegisterSource = false;
private static KeyValuePair<string, string> KeyValuePair = new KeyValuePair<string, string>("joep", "monita");
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//string fileName = $#"{Path}\{FileNameAntarctica}.pbf";
string fileName = $#"{Path}\{FileNameOSPbf}.pbf";
string newFileName = $"{fileName.Replace(".pbf", string.Empty)}-{Guid.NewGuid().ToString().Substring(0, 4)}.pbf";
Console.WriteLine("*** Complete");
string fileNameOutput = CompleteFlow(fileName, newFileName);
Console.WriteLine("");
Console.WriteLine("*** Display");
DisplayFlow(fileNameOutput);
Console.ReadLine();
}
private static string CompleteFlow(string fileName, string newFileName)
{
// 1. Open file and convert to bytes
byte[] fileBytes = FileToBytes(fileName);
// 2. Bytes to OSM stream source (pbf)
PBFOsmStreamSource osmStreamSource;
osmStreamSource = BytesToOsmStreamSource(fileBytes);
osmStreamSource.MoveNext();
if (osmStreamSource.Current() == null)
{
osmStreamSource = FileToOsmStreamSource(fileName);
osmStreamSource.MoveNext();
if (osmStreamSource.Current() == null)
{
throw new Exception("No current in stream.");
}
}
// 3. Add custom tag
AddTag(osmStreamSource);
// 4. OSM stream source to bytes
//byte[] osmStreamSourceBytes = OsmStreamSourceToBytes(osmStreamSource);
// 5. Bytes to file
//string fileNameOutput = BytesToFile(osmStreamSourceBytes, newFileName);
OsmStreamSourceToFile(osmStreamSource, newFileName);
Console.WriteLine(newFileName);
return newFileName;
}
private static void DisplayFlow(string fileName)
{
// 1. Open file and convert to bytes
byte[] fileBytes = FileToBytes(fileName);
// 2. Bytes to OSM stream source (pbf)
BytesToOsmStreamSource(fileBytes);
}
private static byte[] FileToBytes(string fileName)
{
Console.WriteLine(fileName);
return File.ReadAllBytes(fileName);
}
private static PBFOsmStreamSource BytesToOsmStreamSource(byte[] bytes)
{
MemoryStream memoryStream = new MemoryStream(bytes);
memoryStream.Position = 0;
PBFOsmStreamSource osmStreamSource = new PBFOsmStreamSource(memoryStream);
foreach (OsmGeo element in osmStreamSource.Where(osmGeo => osmGeo.Tags.Any(tag => tag.Key.StartsWith(KeyValuePair.Key))))
{
foreach (Tag elementTag in element.Tags.Where(tag => tag.Key.StartsWith(KeyValuePair.Key)))
{
Console.WriteLine("!!!!!!!!!!!!!! Tag found while reading !!!!!!!!!!!!!!!!!!".ToUpper());
}
}
return osmStreamSource;
}
private static PBFOsmStreamSource FileToOsmStreamSource(string fileName)
{
using (FileStream fileStream = new FileInfo(fileName).OpenRead())
{
PBFOsmStreamSource osmStreamSource = new PBFOsmStreamSource(fileStream);
return osmStreamSource;
}
}
private static void AddTag(PBFOsmStreamSource osmStreamSource)
{
osmStreamSource.Reset();
OsmGeo osmGeo = null;
while (osmGeo == null)
{
osmStreamSource.MoveNext();
osmGeo = osmStreamSource.Current();
if(osmGeo?.Tags == null)
{
osmGeo = null;
}
}
osmGeo.Tags.Add("joep", "monita");
Console.WriteLine($"{osmGeo.Tags.FirstOrDefault(tag => tag.Key.StartsWith(KeyValuePair.Key)).Key} - {osmGeo.Tags.FirstOrDefault(tag => tag.Key.StartsWith(KeyValuePair.Key)).Value}");
}
private static byte[] OsmStreamSourceToBytes(PBFOsmStreamSource osmStreamSource)
{
MemoryStream memoryStream = new MemoryStream();
PBFOsmStreamTarget target = new PBFOsmStreamTarget(memoryStream, true);
osmStreamSource.Reset();
target.Initialize();
UpdateTarget(osmStreamSource, target);
target.Flush();
target.Close();
return memoryStream.ToArray();
}
private static string BytesToFile(byte[] bytes, string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
fs.Write(bytes, 0, bytes.Length);
}
return fileName;
}
private static void OsmStreamSourceToFile(PBFOsmStreamSource osmStreamSource, string fileName)
{
using (FileStream fileStream = new FileInfo(fileName).OpenWrite())
{
PBFOsmStreamTarget target = new PBFOsmStreamTarget(fileStream, true);
osmStreamSource.Reset();
target.Initialize();
UpdateTarget(osmStreamSource, target);
target.Flush();
target.Close();
}
}
private static void UpdateTarget(OsmStreamSource osmStreamSource, OsmStreamTarget osmStreamTarget)
{
if (useRegisterSource)
{
osmStreamTarget.RegisterSource(osmStreamSource, osmGeo => true);
osmStreamTarget.Pull();
}
else
{
bool isFirst = true;
foreach (OsmGeo osmGeo in osmStreamSource)
{
Tag? tag = osmGeo.Tags?.FirstOrDefault(t => t.Key == KeyValuePair.Key);
switch (osmGeo.Type)
{
case OsmGeoType.Node:
if (isFirst)
{
for (int indexer = 0; indexer < 1; indexer++)
{
(osmGeo as Node).Tags.Add(new Tag(KeyValuePair.Key + Guid.NewGuid(), KeyValuePair.Value));
}
isFirst = false;
}
osmStreamTarget.AddNode(osmGeo as Node);
break;
case OsmGeoType.Way:
osmStreamTarget.AddWay(osmGeo as Way);
break;
case OsmGeoType.Relation:
osmStreamTarget.AddRelation(osmGeo as Relation);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
}
}
Already I posted this question on the GITHube page of OSMSharp as is linked here. Any help would be very appreciated.
I use bouncycastle in Java
CertificateFactory.getInstance("X509", "BC")
certFactory.generateCertificate(in)
to generate the cert. It works fine. But when I use
x509Certificate.getExtensionValue("1.2.3.4.5.6.7")
The return value does not match the membersrvc's one.
Did I miss some thing?
With bouncycastle you can do this to extract the ASN1 structure of the extension
public ASN1Primitive getExtensionValue(X509Certificate certificate, String oid) throws IOException {
byte[] bytes = certificate.getExtensionValue(oid);
if (bytes == null) {
return null;
}
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
return aIn.readObject();
}
ASN1 is a complex object, you need to parse it to get the desired field. For example to Give back the CA URI meta-data found within the given X509 cert.
public String getIssuerURL(final X509Certificate certificate) throws Exception {
final ASN1ObjectIdentifier ocspAccessMethod = X509ObjectIdentifiers.id_ad_caIssuers;
final byte[] authInfoAccessExtensionValue = certificate.getExtensionValue(Extension.authorityInfoAccess.getId());
if (null == authInfoAccessExtensionValue) {
return null;
}
ASN1InputStream ais1 = null;
ASN1InputStream ais2 = null;
try {
final ByteArrayInputStream bais = new ByteArrayInputStream(authInfoAccessExtensionValue);
ais1 = new ASN1InputStream(bais);
final DEROctetString oct = (DEROctetString) (ais1.readObject());
ais2 = new ASN1InputStream(oct.getOctets());
final AuthorityInformationAccess authorityInformationAccess = AuthorityInformationAccess.getInstance(ais2.readObject());
final AccessDescription[] accessDescriptions = authorityInformationAccess.getAccessDescriptions();
for (AccessDescription accessDescription : accessDescriptions) {
final boolean correctAccessMethod = accessDescription.getAccessMethod().equals(ocspAccessMethod);
if (!correctAccessMethod) {
continue;
}
final GeneralName gn = accessDescription.getAccessLocation();
if (gn.getTagNo() != GeneralName.uniformResourceIdentifier) {
continue;
}
final DERIA5String str = (DERIA5String) ((DERTaggedObject) gn.toASN1Primitive()).getObject();
final String accessLocation = str.getString();
return accessLocation;
}
return null;
} catch (IOException e) {
throw new Exception(e);
} finally {
IOUtils.closeQuietly(ais1);
IOUtils.closeQuietly(ais2);
}
}
To return a human-readable string from an ASN1Primitive
public String getStringFromGeneralName(ASN1Primitive names) throws IOException {
ASN1TaggedObject taggedObject = (ASN1TaggedObject) names ;
return new String(ASN1OctetString.getInstance(taggedObject, false).getOctets(), "ISO-8859-1");
}
I'm trying to build a Sling servlet that returns a modified value of a resource from the JCR. I dont want to change the original resource, so I create a SyntheticResource and make my manipulations. I then return it back using the RequestDispatcher.
The following code doesn't return the Modified content as expected and I don't see any errors in the log either. Can you tell me what I'm doing wrong here
#SlingServlet(methods = "GET", resourceTypes = "sling/components/test", selectors = "test")
public class TestServlet extends SlingSafeMethodsServlet {
/**
*
*/
private static final long serialVersionUID = 4078524820231933974L;
private final Logger log = LoggerFactory.getLogger(getClass());
#Reference
ResourceResolverFactory resolverFactory;
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
Map<String, Object> param = new HashMap<String, Object>();
ResourceResolver resolver = null;
response.setContentType("text/html");
StringWriterResponse writerResponse = new StringWriterResponse(response);
PrintWriter writer = response.getWriter();
try {
param.put(ResourceResolverFactory.SUBSERVICE, "testService");
final String path = request.getRequestPathInfo().getResourcePath();
resolver = resolverFactory.getServiceResourceResolver(param);
final Resource resource = resolver.getResource(path);
String resourceType = resource.getResourceType();
Resource testResource = new SyntheticResource(resolver,
path, resourceType) {
public <T> T adaptTo(Class<T> type) {
if (type == ValueMap.class) {
ModifiableValueMap map = resource
.adaptTo(ModifiableValueMap.class);
map.put("jcr:title", "Modified Title");
return (T)map;
}
return super.adaptTo(type);
}
};
RequestDispatcherOptions requestDispatcherOptions = new RequestDispatcherOptions();
requestDispatcherOptions.setReplaceSelectors("");
final RequestDispatcher requestDispatcher = request.getRequestDispatcher(testResource, requestDispatcherOptions);
requestDispatcher.forward(request, writerResponse);
// log.debug( writerResponse.getString() );
writer.println(writerResponse.getString());
response.setStatus(HttpServletResponse.SC_OK );
} catch (Exception e) {
log.error("Exception: ", e);
} finally {
if( resolver != null) {
resolver.close();
}
if( writer != null ){
writer.close();
}
if (writerResponse != null) {
writerResponse.clearWriter();
}
}
}
}
Using a ResourceDecorator would be simpler, it can return a ResourceWrapper that implements the required changes. Just be careful to keep the decorator's decorate method efficient when it's called for a Resource that it doesn't want to decorate, as it will be called for all Resources.
Wondering if its possible and/or supported to put/post an entire object to REST Webservice, as opposed to just some name/value pairs ?
If so, can a List of objects be put/post-ed as well ?
I figured it may be possible, since a GET request is able to return a List of objects, I'd like to do the "reverse" operation with the updated objects (and not send them one at a time, or worse, in individual pieces via name/value pairs) ?
I understand this is a very basic question, but the approach I've taken so far was to just try and code the PUT and get it working (which works if the PUT function has no arguments, like:
public class AObjectController : ApiController
{
public List<int[]> Put()
{
List<int[]> ret = new List<int[]>();
ret.Add(new int[] {-1, 1111});
ret.Add(new int[] {-2, 2222});
return ret;
}
If I specify a single object, or list of objects, I get exceptions:
public List<int[]> Put(AObject object) **CASE 1**
public List<int[]> Put(List<AObject> objects) **CASE 2**
{
List<int[]> ret = new List<int[]>();
ret.Add(new int[] { -1, 1111 });
ret.Add(new int[] { -2, 2222 });
return ret;
}
CASE 1: public List(int[]) Put(AObject object)
CASE 2: public List(int[]) Put(List(AObject) objects)
Heres the code on the client side that is making the call:
public int writeAll(List<T> data)
{
_sendBuffer =
JsonConvert.SerializeObject(
tabletData,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }
);
byte[] b = StringHelper.GetBytes(_sendBuffer);
string url = ContructUrlRequest(null, null);
WebRequest request = WebRequest.Create(url);
request.Method = "PUT";
request.ContentType = "application/json";
request.ContentLength = b.Length;
request.Credentials = CredentialCache.DefaultCredentials;
((HttpWebRequest)request).UserAgent = "...";
//((HttpWebRequest)request).AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(b, 0, b.Length);
requestStream.Flush();
requestStream.Close();
}
WebResponse response = request.GetResponse();
if (response == null)
{
return -1;
}
StreamReader sr = new StreamReader(response.GetResponseStream()); ;
_recieveBuffer = sr.ReadToEnd();
List<int[]> _resultData = JsonConvert.DeserializeObject<List<int[]>>(
_recieveBuffer,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }
);
return data.Count;
}
Thank you.
Used the serialization write code from server on my client side and it worked
public int writeAll(List<AObject> aObjects)
{
string url = ContructUrlRequest(null, null);
WebRequest request = WebRequest.Create(url);
request.Method = WebRequestMethods.Http.Put;
request.ContentType = "application/json; charset=utf-8";
request.Credentials = CredentialCache.DefaultCredentials;
((HttpWebRequest)request).UserAgent = "going insane";
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.TypeNameHandling = TypeNameHandling.Objects | TypeNameHandling.Arrays;
serializerSettings.Converters.Add(new IsoDateTimeConverter());
JsonSerializer serializer = JsonSerializer.Create(serializerSettings);
using (Stream requestStream = request.GetRequestStream())
{
using (StreamWriter streamWriter = new StreamWriter(requestStream, new UTF8Encoding(false, true)))
{
using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter))
{
serializer.Serialize(jsonTextWriter, aObjects);
}
}
}
WebResponse response = request.GetResponse();
if (response == null)
{
Log.Info(FIDB.TAG_WSBUFFER, "WSBuffer.writeAll: response = NULL");
return -1;
}
StreamReader sr = new StreamReader(response.GetResponseStream());
_recieveBuffer = sr.ReadToEnd();
_resultData = JsonConvert.DeserializeObject<List<int[]>>(
_recieveBuffer,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }
);
return tabletData.Count;
}