Asp.net web api json interraction - asp.net

Hi there i am developing an azure web api and my put method is below
public string[] Put(SampleRequest request)
{
//Getting Request initials
string[] filmNames = request.Inputs.FilmIds;
int userAge = request.Inputs.UserAge;
char userGender = request.Inputs.UserGender;
int userId = request.Inputs.UserId;
.
.
. Doesnt matter rest of them...
When i tried to communicate with json the request(which is a SampleRequest object) in my put method is getting null so that i cannot parse it to get the data in it, what would be the problem ? My data model,help page json format and my json request(which is in another app) is below
public class SampleRequest
{
public InputsRequest Inputs { get; set; }
}
public class InputsRequest
{
public int UserId { get; set; }
public int UserAge { get; set; }
public char UserGender { get; set; }
public string[] FilmIds { get; set; }
}
application/json, text/json [ API HELP PAGE ]
Sample:
{
"Inputs": {
"UserId": 1,
"UserAge": 2,
"UserGender": "A",
"FilmIds": [
"sample string 1",
"sample string 2"
]
}
}
my request from other app:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:5291/api/values");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "PUT";
var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream());
string json = "{"+"\"Inputs\""+":"+"{"+ "\"UserId\"" + ":" + "12345" + ","
+ "\"UserAge\"" + ":" + "23" + ","
+ "\"UserGender\"" + ":" + "\"M\"" + ","
+ "\"FilmIds\"" + ":" +
"[\"Kung Fu Panda\",\"I Am Legend\",\"I Am Number Four\"]"+
"}"+"}";
streamWriter.Write(json);
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
}
Quick Note: Yes i know the name is FilmIds but i am getting Film names :D dont worry about it

This problem is coming from async methods , the reason behind getting null from put function is that the test application is not sending all of its messages so that the put method gets nothing , solution is using Putasync method below
using (var htc = new HttpClient())
{
var res = await htc.PutAsync("http://localhost:5291/api/values", new StringContent(serializedObject, Encoding.UTF8, "application/json"));
}

Related

Issue with loading dicom images in WADO loader

I am working on a web based OHIF Dicom viewer. I am using clear canvas as my PACs server. So I developed one broker application in .net core which works like WADO-RS and supply information to OHIF viewer from clear canvas. In my broker application I am passing metadata to OHIF viewer in json format by using FO-dicom json converter which converts dcm file into Json string.
My code for sending metadata:
var files = Directory.GetFiles(directory);
List<JObject> lstjo = new List<JObject>();
JObject jo;
foreach (var file in files)
{
var dicomDirectory = DicomFile.Open(file, FileReadOption.ReadAll);
if (dicomDirectory.Dataset.InternalTransferSyntax.UID.UID != DicomTransferSyntax.ImplicitVRLittleEndian.UID.UID)
{
var transcoder = new DicomTranscoder(dicomDirectory.Dataset.InternalTransferSyntax, DicomTransferSyntax.ImplicitVRLittleEndian);
dicomDirectory = transcoder.Transcode(dicomDirectory);
}
JsonDicomConverter dicomConverter = new JsonDicomConverter();
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
JsonWriter writer = new JsonTextWriter(sw);
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
dicomConverter.WriteJson(writer, dicomDirectory.Dataset, serializer);
jo = JObject.Parse(sb.ToString());
// jo.Property("7FE00010").Remove();
retJsonstring += jo.ToString() + ",";
}
if (retJsonstring.Length > 6)
{
retJsonstring = retJsonstring.Substring(0, retJsonstring.Length - 1) + "]";
}
else
{
retJsonstring += "]";
}
retJsonstring = retJsonstring.Replace("\r", "").Replace("\n", "");
}
return retJsonstring;
During passing metadata there is no issue in Ohif viewer. After then OHIF viewer sending WADORS request for frames to display. My broker application also send responding for that request in multipart.
My code for sending Multipart response :
{
var dicomFile = DicomFile.Open(path, FileReadOption.ReadAll);
string transfersyntax = dicomFile.Dataset.InternalTransferSyntax.UID.UID;
MemoryStream streamContent = new MemoryStream();
if (transfersyntax != DicomTransferSyntax.ImplicitVRLittleEndian.UID.UID)
{
var transcoder = new DicomTranscoder(dicomFile.Dataset.InternalTransferSyntax, DicomTransferSyntax.ImplicitVRLittleEndian);
dicomFile = transcoder.Transcode(dicomFile);
}
dicomFile.Save(streamContent);
DicomImage img = new DicomImage(dicomFile.Dataset, 0);
streamContent.Seek(0, SeekOrigin.Begin);
string boundary = Guid.NewGuid().ToString();
MultipartContent multipartContent = new MultipartContent();
//newFile.Save(multipartContent.Stream);
multipartContent.Stream = streamContent;// File.OpenRead(path);
multipartContent.ContentType = "application/octet-stream";
multipartContent.transfersyntax = dicomFile.Dataset.InternalTransferSyntax.UID.UID;
multipartContent.FileName = "";
multiContentResult = new MultipartResult("related", boundary) { multipartContent };
return multiContentResult;
}
Mulitpart class and MulticontentResult Class:
public class MultipartContent
{
public string ContentType { get; set; }
public string FileName { get; set; }
public Stream Stream { get; set; }
public string transfersyntax { get; set; }
}
public class MultipartResult : Collection<MultipartContent>, IActionResult
{
private readonly System.Net.Http.MultipartContent content;
public MultipartResult(string subtype = "byteranges", string boundary = null)
{
if (boundary == null)
{
this.content = new System.Net.Http.MultipartContent(subtype);
}
else
{
this.content = new System.Net.Http.MultipartContent(subtype, boundary);
}
}
public async Task ExecuteResultAsync(ActionContext context)
{
foreach (var item in this)
{
if (item.Stream != null)
{
var content = new StreamContent(item.Stream);
if (item.ContentType != null)
{
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(item.ContentType);
content.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("transfer-syntax", item.transfersyntax));
}
this.content.Add(content);
}
}
context.HttpContext.Response.ContentLength = content.Headers.ContentLength;
context.HttpContext.Response.ContentType = content.Headers.ContentType.ToString();
await content.CopyToAsync(context.HttpContext.Response.Body);
}
}
After sending WAROrs response , I getting error in OHIF viewer in RangeError: offset is out of bounds in stackviewport.js during set pixeldata flat32array to scaledata flat32array like below Image
So I inspect in browser after then I come know that Pixel data size and scaledata size is different like below image..
To verify my dcm file I checked with ohif viewer by directly opened those file in https://v3-demo.ohif.org/local. It is opening properly.
So what are possible reason for this issue ? how to rectify?

How to send a zipped file to S3 bucket from Apex?

Folks,
I am trying to move data to s3 from Salesforce using apex class. I have been told by the data manager to send the data in zip/gzip format to the S3 bucket for storage cost savings.
I have simply tried to do a request.setCompressed(true); as I've read it compresses the body before sending it to the endpoint. Code below:
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:'+DATA_NAMED_CRED+'/'+URL+'/'+generateUniqueTimeStampforSuffix());
request.setMethod('PUT');
request.setBody(JSON.serialize(data));
request.setCompressed(true);
request.setHeader('Content-Type','application/json');
But no matter what I always receive this:
<Error><Code>XAmzContentSHA256Mismatch</Code><Message>The provided 'x-amz-content-sha256' header does not match what was computed.</Message><ClientComputedContentSHA256>fd31b2b9115ef77e8076b896cb336d21d8f66947210ffcc9c4d1971b2be3bbbc</ClientComputedContentSHA256><S3ComputedContentSHA256>1e7f2115e60132afed9e61132aa41c3224c6e305ad9f820e6893364d7257ab8d</S3ComputedContentSHA256>
I have tried multiple headers too, like setting the content type to gzip/zip, etc.
Any pointers in the right direction would be appreciated.
I had a good amount of headaches attempting to do a similar thing. I feel your pain.
The following code has worked for us using lambda functions; you can try modifying it and see what happens.
public class AwsApiGateway {
// Things we need to know about the service. Set these values in init()
String host, payloadSha256;
String resource;
String service = 'execute-api';
String region;
public Url endpoint;
String accessKey;
String stage;
string secretKey;
HttpMethod method = HttpMethod.XGET;
// Remember to set "payload" here if you need to specify a body
// payload = Blob.valueOf('some-text-i-want-to-send');
// This method helps prevent leaking secret key,
// as it is never serialized
// Url endpoint;
// HttpMethod method;
Blob payload;
// Not used externally, so we hide these values
Blob signingKey;
DateTime requestTime;
Map<String, String> queryParams = new map<string,string>(), headerParams = new map<string,string>();
void init(){
if (payload == null) payload = Blob.valueOf('');
requestTime = DateTime.now();
createSigningKey(secretKey);
}
public AwsApiGateway(String resource){
this.stage = AWS_LAMBDA_STAGE
this.resource = '/' + stage + '/' + resource;
this.region = AWS_REGION;
this.endpoint = new Url(AWS_ENDPOINT);
this.accessKey = AWS_ACCESS_KEY;
this.secretKey = AWS_SECRET_KEY;
}
// Make sure we can't misspell methods
public enum HttpMethod { XGET, XPUT, XHEAD, XOPTIONS, XDELETE, XPOST }
public void setMethod (HttpMethod method){
this.method = method;
}
public void setPayload (string payload){
this.payload = Blob.valueOf(payload);
}
// Add a header
public void setHeader(String key, String value) {
headerParams.put(key.toLowerCase(), value);
}
// Add a query param
public void setQueryParam(String key, String value) {
queryParams.put(key.toLowerCase(), uriEncode(value));
}
// Create a canonical query string (used during signing)
String createCanonicalQueryString() {
String[] results = new String[0], keys = new List<String>(queryParams.keySet());
keys.sort();
for(String key: keys) {
results.add(key+'='+queryParams.get(key));
}
return String.join(results, '&');
}
// Create the canonical headers (used for signing)
String createCanonicalHeaders(String[] keys) {
keys.addAll(headerParams.keySet());
keys.sort();
String[] results = new String[0];
for(String key: keys) {
results.add(key+':'+headerParams.get(key));
}
return String.join(results, '\n')+'\n';
}
// Create the entire canonical request
String createCanonicalRequest(String[] headerKeys) {
return String.join(
new String[] {
method.name().removeStart('X'), // METHOD
new Url(endPoint, resource).getPath(), // RESOURCE
createCanonicalQueryString(), // CANONICAL QUERY STRING
createCanonicalHeaders(headerKeys), // CANONICAL HEADERS
String.join(headerKeys, ';'), // SIGNED HEADERS
payloadSha256 // SHA256 PAYLOAD
},
'\n'
);
}
// We have to replace ~ and " " correctly, or we'll break AWS on those two characters
string uriEncode(String value) {
return value==null? null: EncodingUtil.urlEncode(value, 'utf-8').replaceAll('%7E','~').replaceAll('\\+','%20');
}
// Create the entire string to sign
String createStringToSign(String[] signedHeaders) {
String result = createCanonicalRequest(signedHeaders);
return String.join(
new String[] {
'AWS4-HMAC-SHA256',
headerParams.get('date'),
String.join(new String[] { requestTime.formatGMT('yyyyMMdd'), region, service, 'aws4_request' },'/'),
EncodingUtil.convertToHex(Crypto.generateDigest('sha256', Blob.valueof(result)))
},
'\n'
);
}
// Create our signing key
void createSigningKey(String secretKey) {
signingKey = Crypto.generateMac('hmacSHA256', Blob.valueOf('aws4_request'),
Crypto.generateMac('hmacSHA256', Blob.valueOf(service),
Crypto.generateMac('hmacSHA256', Blob.valueOf(region),
Crypto.generateMac('hmacSHA256', Blob.valueOf(requestTime.formatGMT('yyyyMMdd')), Blob.valueOf('AWS4'+secretKey))
)
)
);
}
// Create all of the bits and pieces using all utility functions above
public HttpRequest createRequest() {
init();
payloadSha256 = EncodingUtil.convertToHex(Crypto.generateDigest('sha-256', payload));
setHeader('date', requestTime.formatGMT('yyyyMMdd\'T\'HHmmss\'Z\''));
if(host == null) {
host = endpoint.getHost();
}
setHeader('host', host);
HttpRequest request = new HttpRequest();
request.setMethod(method.name().removeStart('X'));
if(payload.size() > 0) {
setHeader('Content-Length', String.valueOf(payload.size()));
request.setBodyAsBlob(payload);
}
String finalEndpoint = new Url(endpoint, resource).toExternalForm(),
queryString = createCanonicalQueryString();
if(queryString != '') {
finalEndpoint += '?'+queryString;
}
request.setEndpoint(finalEndpoint);
for(String key: headerParams.keySet()) {
request.setHeader(key, headerParams.get(key));
}
String[] headerKeys = new String[0];
String stringToSign = createStringToSign(headerKeys);
request.setHeader(
'Authorization',
String.format(
'AWS4-HMAC-SHA256 Credential={0}, SignedHeaders={1},Signature={2}',
new String[] {
String.join(new String[] { accessKey, requestTime.formatGMT('yyyyMMdd'), region, service, 'aws4_request' },'/'),
String.join(headerKeys,';'), EncodingUtil.convertToHex(Crypto.generateMac('hmacSHA256', Blob.valueOf(stringToSign), signingKey))}
));
system.debug(json.serializePretty(request.getEndpoint()));
return request;
}
// Actually perform the request, and throw exception if response code is not valid
public HttpResponse sendRequest(Set<Integer> validCodes) {
HttpResponse response = new Http().send(createRequest());
if(!validCodes.contains(response.getStatusCode())) {
system.debug(json.deserializeUntyped(response.getBody()));
}
return response;
}
// Same as above, but assume that only 200 is valid
// This method exists because most of the time, 200 is what we expect
public HttpResponse sendRequest() {
return sendRequest(new Set<Integer> { 200 });
}
// TEST METHODS
public static string getEndpoint(string attribute){
AwsApiGateway api = new AwsApiGateway(attribute);
return api.createRequest().getEndpoint();
}
public static string getEndpoint(string attribute, map<string, string> params){
AwsApiGateway api = new AwsApiGateway(attribute);
for (string key: params.keySet()){
api.setQueryParam(key, params.get(key));
}
return api.createRequest().getEndpoint();
}
public class EndpointConfig {
string resource;
string attribute;
list<object> items;
map<string,string> params;
public EndpointConfig(string resource, string attribute, list<object> items){
this.items = items;
this.resource = resource;
this.attribute = attribute;
}
public EndpointConfig setQueryParams(map<string,string> parameters){
params = parameters;
return this;
}
public string endpoint(){
if (params == null){
return getEndpoint(resource);
} else return getEndpoint(resource + '/' + attribute, params);
}
public SingleRequestMock mockResponse(){
return new SingleRequestMock(200, 'OK', json.serialize(items), null);
}
}
}

Why is my DataContractJsonSerializer failing on the call to ReadObject()?

I am trying to deserialize some json received from a Web API method being called from a .NET 3.5 Winforms app based on this code: http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
The json is being returned, but upon deserialization, it is failing to grab root and therefore growling:
Here is the client code in question:
try
{
var client = new RestClient();
client.BaseUrl = "http://localhost:48614/"; // <-- this works
var request = new RestRequest();
request.Resource = "api/departments/"; // can replace this with other data, such as redemptions, etc.
RestResponse response = client.Execute(request) as RestResponse;
if ((response.StatusCode == HttpStatusCode.OK) && (response.ResponseStatus == ResponseStatus.Completed)) // Both are probably not necessary
{
MessageBox.Show(string.Format("Content is {0}", response.Content));
// from http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
MemoryStream deptStream = new MemoryStream();
DataContractJsonSerializer cereal = new DataContractJsonSerializer(typeof(Department));
deptStream.Position = 0;
Department dept = (Department)cereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
}
else
{
MessageBox.Show(string.Format("Status code is {0} ({1}); response status is {2}",
response.StatusCode, response.StatusDescription, response.ResponseStatus));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The response.Content line is doing just fine, displaying the json data in the dialog.
The Department data is defined this way in the .NET 4 ASP.NET / Web API app:
namespace DuckbilledPlatypusServerWebAPI.Models
{
public class Department
{
[Key]
public int Id { get; set; }
[Required]
public string AccountId { get; set; }
[Required]
public string DeptName { get; set; }
}
}
...and this way in the .NET 3.5 Winforms app that receives the data:
[DataContract]
public class Department
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string AccountId { get; set; }
[DataMember]
public string DeptName { get; set; }
}
So what does it yet need to work? How am I to supply it with a 'root' element, as it seems to be demanding?
UPDATE
Badri's answer solves the err msg, but I'm still not getting any data to work with the DataContractJsonSerializer, or I'm accessing it wrong. Here is my code now:
MessageBox.Show(string.Format("Content is {0}", response.Content));
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
DataContractJsonSerializer jasonCereal = new DataContractJsonSerializer(typeof(Department));
Department dept = (Department)jasonCereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
...and, although the first message box shows the jsonarray:
...the second one says accountId and deptName are empty strings. In what way am I maltrreating DataContractJsonSerializer?
deptStream is newed up but where do you load the JSON response returned into the MemoryStream, before the deserialization. You should do something like this.
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
// Deserialize now
UPDATE
Your JSON corresponds to a list of Department objects not a single Department object. Try something like this.
var jasonCereal = new DataContractJsonSerializer(typeof(List<Department>));
var depts = (List<Department>)jasonCereal.ReadObject(deptStream);
foreach(var dept in depts)
MessageBox.Show(
String.Format("accountId is {0}, deptName is {1}",
dept.AccountId, dept.DeptName));

Consume form data by wcf service sending by post

I read some articles about this and I find that to achive that wcf get data from post request we add
[ServiceContract]
public interface IService1 {
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/GetData")]
void GetData(Stream data);
}
and in implementation
public string GetData( Stream input)
{
long incomingLength = WebOperationContext.Current.IncomingRequest.ContentLength;
string[] result = new string[incomingLength];
int cnter = 0;
int arrayVal = -1;
do
{
if (arrayVal != -1) result[cnter++] = Convert.ToChar(arrayVal).ToString();
arrayVal = input.ReadByte();
} while (arrayVal != -1);
return incomingLength.ToString();
}
My question is what should I do that in submit action in form request will send to my service and consume?
In Stream parameter will I have post information from form to which I could get by Request["FirstName"]?
Your code isn't decoding the request body correctly - you're creating an array of string values, each one with one character. After getting the request body, you need to parse the query string (using HttpUtility is an easy way to do so). The code below shows how to get the body and one of the fields correctly.
public class StackOverflow_7228102
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/GetData")]
string GetData(Stream data);
}
public class Service : ITest
{
public string GetData(Stream input)
{
string body = new StreamReader(input).ReadToEnd();
NameValueCollection nvc = HttpUtility.ParseQueryString(body);
return nvc["FirstName"];
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
WebClient c = new WebClient();
c.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
Console.WriteLine(c.UploadString(baseAddress + "/GetData", "FirstName=John&LastName=Doe&Age=33"));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

WebInvoke with UriTemplate with empty strings

How does the WebInvokeAttribute and UriTemplate resolver behave when supplied with empty strings in placeholders at runtime?
The documentation doesn't seem to cover this.
In some inherited code, I'm getting situations where the methods are not being resolved properly when empty strings are passed. There is no obvious conflict with other web methods.
Thanks!
Update:
In a UriTemplate such as: "/{x}/{y}?z={z}", what is the behavior if some or all of the values are provided as "" empty strings, but the delimiters remain, "/17/?z=", "//apple?z=", "//?z=%20", "//?z=". Also, by standard, are browsers allowed to clean up URIs before sending them?
The empty string means that the URI for the operation is located at the same address as the endpoint - see the example below for more information.
public class StackOverflow_6267866
{
[ServiceContract]
public interface ITest1
{
[WebInvoke(UriTemplate = "")]
string EchoString(string text);
}
[ServiceContract]
public interface ITest2
{
[WebInvoke(UriTemplate = "", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
int Add(int x, int y);
}
public class Service : ITest1, ITest2
{
public string EchoString(string text)
{
return text;
}
public int Add(int x, int y)
{
return x + y;
}
}
static void SendPostRequest(string uri, string contentType, string body)
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
req.Method = "POST";
req.ContentType = contentType;
byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
req.GetRequestStream().Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
foreach (string headerName in resp.Headers.AllKeys)
{
Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
}
Console.WriteLine();
Stream respStream = resp.GetResponseStream();
Console.WriteLine(new StreamReader(respStream).ReadToEnd());
Console.WriteLine();
Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* ");
Console.WriteLine();
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest1), new WebHttpBinding(), "ITest1").Behaviors.Add(new WebHttpBehavior());
host.AddServiceEndpoint(typeof(ITest2), new WebHttpBinding(), "ITest2").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
SendPostRequest(baseAddress + "/ITest1", "application/json", "\"hello world\"");
SendPostRequest(baseAddress + "/ITest1/", "application/json", "\"hello world\"");
SendPostRequest(baseAddress + "/ITest2", "application/json", "{\"x\":123,\"y\":456}");
SendPostRequest(baseAddress + "/ITest2/", "application/json", "{\"x\":123,\"y\":456}");
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Resources