I am trying to send a KML file (which is XML) by HTTP Post to an ASPX page. This works as long as there is no escaped HTML contained in the KML.
To create the KML I use the following class for the XmlSerializer
public class kml
{
[DataMember]
public DocumentItem Document
{ get; set; }
public kml()
{
}
public class BalloonStyleItem
{
[DataMember]
public string text
{ get; set; }
[DataMember]
public string displayMode
{ get; set; }
public BalloonStyleItem()
{
displayMode = "default";
}
}
}
//(...)
In my code, that creates the KML I have this line:
balloonStyleItem.text = "<h2>name: " + substation.name + "</h2>region: " + substation.Region.Region.name + "<br>subregion: " + substation.Region.name;
As you see it contains HTML
Now I want to send this KML by HTTP Post:
HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
Stream stream = request.EndGetRequestStream(asyncResult);
StreamWriter writer = new StreamWriter(stream);
System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(kml));
xmlSerializer.Serialize(writer, kmlContainer);
writer.Write(xmlstring); //here it crashes!
At this point the execution of the program stops with the error message "WebException was unhadled by user code, The remote server returned an error: NotFound"
If I give something like
balloonStyleItem.text = "xxxxx";
(without HTML) everything works fine. Do you have any ideas?
Can you give it a try using DataContractSerializer instead of XmlSerializer? I noticed that you are using attributes designed for DataContractSerializer...
DataContractSerializer ser = new DataContractSerializer(typeof(kml));
ser.WriteObject(stream, kmlContainer);
Related
I'm not a developer and we don't have one currently on our staff. So I looked all over the web and modified this Apex Class to suit my needs so that when an opportunity is marked as closed/won I get a small message in Slack.
It works great and I'd like to send this to Production. However, I didn't realize that I need to include a test for this and I am stuck on what that means.
Here's my Apex Class:
public with sharing class SlackPublisher {
private static final String SLACK_URL = 'https://hooks.slack.com/services/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';
public class Oppty {
#InvocableVariable(label='Opportunity Name')
public String opptyName;
#InvocableVariable(label='Opportunity Owner')
public String opptyOwnerName;
#InvocableVariable(label='Account Name')
public String acctName;
#InvocableVariable(label='Amount')
public String amount;
}
public class UrlMethods {
String BaseUrl; // The Url w/o the page (ex: 'https://na9.salesforce.com/')
String PageUrl; // The Url of the page (ex: '/apex/SomePageName')
String FullUrl; // The full Url of the current page w/query string parameters
// (ex: 'https://na9.salesforce.com/apex/SomePageName?x=1&y=2&z=3')
String Environment; // Writing code that can detect if it is executing in production or a sandbox
// can be extremely useful especially if working with sensitive data.
public UrlMethods() { // Constructor
BaseUrl = URL.getSalesforceBaseUrl().toExternalForm(); // (Example: 'https://na9.salesforce.com/')
}
}
#InvocableMethod(label='Post to Slack')
public static void postToSlack ( List<Oppty> opps ) {
Oppty o = opps[0]; // bulkify the code later
Map<String,Object> msg = new Map<String,Object>();
msg.put('text','Deal ' + o.opptyName + ' was just Closed/Won' + ':champagne:' + '\n' + 'for a total of ' + '$' + o.amount);
msg.put('mrkdwn', true);
String body = JSON.serialize(msg);
System.enqueueJob(new QueueableSlackPost(SLACK_URL, 'POST', body));
}
public class QueueableSlackPost implements System.Queueable, Database.AllowsCallouts {
private final String url;
private final String method;
private final String body;
public QueueableSlackPost(String url, String method, String body) {
this.url = url;
this.method = method;
this.body = body;
}
public void execute(System.QueueableContext ctx) {
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(method);
req.setBody(body);
Http http = new Http();
HttpResponse res = http.send(req);
}
}
}
and what I found online as a base for a test was this:
#isTest
private class SlackOpportunityPublisherTest {
private class RestMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
String fullJson = 'your Json Response';
HTTPResponse res = new HTTPResponse();
res.setHeader('Content-Type', 'text/json');
res.setBody(fullJson);
res.setStatusCode(200);
return res;
}
}
static testMethod void service_call() {
Test.setMock(HttpCalloutMock.class, new RestMock());
Test.startTest();
//your webserive call code
Database.GetUpdatedResult r =
Database.getUpdated(
'amount',
Datetime.now().addHours(-1),
Datetime.now());
Test.StopTest();
}
}
When I try to validate this in production it says it only gives me 68% coverage and I need 75%. Can someone help me write the test so that I can put into Prod?
I have an image saved in my database.
public class FileData
{
[Key]
public Guid Oid { get; set; }
public int size { get; set; }
public string FileName { get; set; }
public byte[] Content { get; set; }
}
I want to return the file from my web api (.Net Core 3.1). I have tried this code. The image is returned, but appears damaged, cannot be seen.
public async Task<ActionResult> GetFileData(Guid id)
{
var fileData = await _context.FileData.FindAsync(id);
if (fileData == null)
{
return NotFound();
}
MemoryStream ms = new MemoryStream(fileData.Content);
ms.Seek(0, SeekOrigin.Begin);
string contentType = System.Net.Mime.MediaTypeNames.Application.Octet;
return File(ms.ToArray(), contentType, fileData.FileName);
}
How can I do it?
Your return type seems off. You could specify a Mime type for images, e.g. "ìmage/jpeg" for JPEG files.
I do have a similar code to read images previously uploaded to an Azure blobstorage. Apart from the way you load the byte array into the MemoryStream, the overall parameters of the function look the same.
Try
return File(ms, "image/jpeg");
instead.
I have a API which is returning a complex JSON and I want to consume that API in Angular-v5 using HTTPClient. I have successfully consumed that API, but the problem is when I want to extract Collections serialized in JSON and map to local arrays in TypeScript then it throws error of undefined for local array and when I try to access the PolicyDetail (which is a Typescript class) properties navigating through like policydetail.policyForms then it throws undefined error, and cannot be used in HTML template that's why.
Although it PolicyDetail.name and other properties works except collections.
Note: API Response is coming and I have tested in Swagger and also seen in Network tap.
Model Coming From API
public class PolicyDetailViewModel
{
public string Name { get; set; }
public string Ref { get; set; }
public ICollection<PolicyDataViewModel> Purpose { get; set; } = new List<PolicyDataViewModel>();
public ICollection<PolicyDataViewModel> Objectives { get; set; } = new List<PolicyDataViewModel>();
public ICollection<DefinitionTermViewModel> Definitions { get; set; } = new List<DefinitionTermViewModel>();
public ICollection<PolicyReferenceViewModel> References { get; set; } = new List<PolicyReferenceViewModel>();
public ICollection<PolicyDataViewModel> Policy { get; set; } = new List<PolicyDataViewModel>();
public ICollection<PolicyDataViewModel> Procedure { get; set; } = new List<PolicyDataViewModel>();
public ICollection<FormViewModel> Forms { get; set; } = new List<FormViewModel>();
public string SupportingInformation { get; set; }
public ICollection<PolicyDataViewModel> Outstanding { get; set; } = new List<PolicyDataViewModel>();
public ICollection<int> SelectedPackages { get; set; } = new List<int>();
public ICollection<int> SelectedRegions { get; set; } = new List<int>();
public bool AnyChanges { get; set; }
public bool IsNewPolicy { get; set; }
}
TypeScript Class
export class PolicyDetail extends AuditableBase
{
name:string;
ref:string;
policyInfo:string;
keyFactsForStaff: string;
policyDataDetails: Array<PolicyDataDetail> = new Array<PolicyDataDetail>();
policyDefinitionTerms: Array<PolicyDefinitionTerm>= new Array<PolicyDefinitionTerm>();
policyreferences: Array<PolicyReference> = new Array<PolicyReference>();
policyForms: Array<PolicyForm> = new Array<PolicyForm>();
selectedKloes: Array<number> = new Array <number>();
selectedRegions: Array<number> = new Array<number>();
selectedClusters: Array<number> = new Array<number>();
selectedLegislations: Array<number> = new Array<number>();
}
Maping Result of HttpRequest To TypeScript
export class PolicyDetailComponent {
public policy: PolicyDetail = new PolicyDetail();
public forms: Array<PolicyForm> = new Array<PolicyForm>();
public policyId: number;
constructor(private policyDetailSvc: PolicyDetailSvc,
private router: Router) { }
getPolicyDetail() {
this.policyDetailSvc.getPolicy(this.policyId).subscribe((result) => {
this.policy = result,//it works
this.forms = result.policyForms; // it doesn't
console.log(result, 'Result - Subscribed'),//it works and shows complete object in JSON
console.log(this.policy, 'This.Policy- Subscribed'),//it works and shows complete object in JSON
console.log(this.forms, 'Forms'),//undefined
console.log(result.policyForms, 'Result Forms'),//undefined
console.log(result.policyreferences, 'Result References')//undefined
});
}
}
Problem is Mapping Forms Arrays and other collection objects
I tried using Local property of forms: PolicyForm[]; but it throws undefined.
I tried accessing Policy.PolicyForms but it also throws undefined
I think I'm taking Typescript as C#, but don't know where I am making mistakes.
If my question is not clear then kindly let me know, I'll clear any other confusion.
Parsing
From what I can see in your question, if you have a raw JSON string in your response, you need to parse it into a JavaScript object...
const policyDetail = JSON.parse(result);
This will work if the result is a string, containing a JSON serialization.
C# Land vs TypeScript Land
Another issue you may find is that your C# class has names such as Name and Ref, so if you are serializing with these names, you'll need to match the casing in the TypeScript...
this.forms = result.PolicyForms
// ^
The problem was accessing the response with wrong collection names, I was getting Forms but I was trying to access using PolicyForms.
So I change the PolicyForms to Forms and end so on and it is working as perfectly it should be.
this.forms = result.policyForms;//it was not working because JSON response was coming forms:[], not PolicyForms:[].
this.forms=result.forms;//
I'm trying to send a IEnumerable from a web api controller to a AngularJs controller.
The code I was using was
Web Api:
readonly InventoryEntities _db = new InventoryEntities();
public IEnumerable<FDVOEligibilityRequest> Get()
{
return _db.FDVOEligibilityRequests.AsEnumerable();
}
AngularJS:
//get all customer information
$http.get("/api/Customer/").success(function (data) {
$scope.requests = data;
$scope.loading = false;
})
.error(function () {
$scope.error = "An Error has occured while loading posts!";
$scope.loading = false;
});
This worked fine, but now I'm using linq to include related tables and it doesn't work. The angularJs code is the same.
What am I doing wrong?
readonly InventoryEntities _db = new InventoryEntities();
public IEnumerable<FDVOEligibilityRequest> Get()
{
return _db.FDVOEligibilityRequests
.Include("FDVOEligibilityRequestMandatoryField")
.Include("FDVOEligibilityRequestDCCField").AsEnumerable();
}
I do get the data I want in the controller, but when i try to send it back to angular, I get a 500 (Internal Server Error) angular.js:10722
This is what FDVOEligibilityRequest looks like in the new Web Api controller
public partial class FDVOEligibilityRequest
{
public int Id { get; set; }
public string TestName { get; set; }
public string GroupName { get; set; }
public int MandatoryFieldsID { get; set; }
public int DCCFieldsID { get; set; }
public virtual FDVOEligibilityRequestMandatoryField FDVOEligibilityRequestMandatoryField { get; set; }
public virtual FDVOEligibilityRequestDCCField FDVOEligibilityRequestDCCField { get; set; }
}
If it's 500 and happens after you successfully make a return from your action then it can be an exception during serialization.
I would suggest to check that there are no circular references between FDVOEligibilityRequest and FDVOEligibilityRequestMandatoryField/FDVOEligibilityRequestDCCField.
Or try to diagnose it using code from here:
string Serialize<T>(MediaTypeFormatter formatter, T value)
{
// Create a dummy HTTP Content.
Stream stream = new MemoryStream();
var content = new StreamContent(stream);
/// Serialize the object.
formatter.WriteToStreamAsync(typeof(T), value, stream, content, null).Wait();
// Read the serialized string.
stream.Position = 0;
return content.ReadAsStringAsync().Result;
}
try {
var val = _db.FDVOEligibilityRequests
.Include("FDVOEligibilityRequestMandatoryField")
.Include("FDVOEligibilityRequestDCCField").AsEnumerable();
var str = Serialize(new JsonMediaTypeFormatter(), val);
}
catch (Exception x)
{ // break point here
}
ps: the common suggestion in this case is to use DTOs instead of EF objects with something like Automapper.
I'm trying to consume a RESTful JSON web service using WCF on the client side. The service is 3rd party, so I cannot make any changes to the server response.
The server is sending back a response that looks something like this when there's only one data point...
Single Data Point
{
"Data":
{
"MyPropertyA":"Value1",
"MyPropertyB":"Value2"
},
}
and something like this when there's more than one data point...
Multiple Data Points
{
"Data":
[
{
"MyPropertyA":"Value1",
"MyPropertyB":"Value2"
},
{
"MyPropertyA":"Value3",
"MyPropertyB":"Value4"
},
{
"MyPropertyA":"Value5",
"MyPropertyB":"Value6"
}
],
}
I have my service contract set up like this...
[ServiceContract]
public interface IRewardStreamService
{
[OperationContract]
[WebInvoke]
MyResponse GetMyStuff();
}
and a data point's data contract like this...
[DataContract]
public class MyData
{
[DataMember]
public string MyPropertyA { get; set; }
[DataMember]
public string MyPropertyB { get; set; }
}
and the only way I can get the single data point response to work is if I have a single instance property like this, but this does not parse the multiple data point response...
Response for Single Instance
[DataContract]
public class MyResponse
{
[DataMember]
public MyData Data { get; set; }
}
and the only way I can get the multiple data point response to work is if I have an array / list instance property like this, but this does not parse the single data point response...
Response for Multiple Instance
[DataContract]
public class MyResponse
{
[DataMember]
public IList<MyData> Data { get; set; }
}
I understand the issue is that the response is omitting the brackets when there's only one data point returned, but it seems that WCF doesn't play well with deserializing that syntax. Is there some way I can tell the DataContractJsonSerializer to allow single element arrays to not include brackets and then tell my service to use that serializer? Maybe a service behavior or something?
Any direction would be helpful.
You can use a custom message formatter to change the deserialization of the JSON into the data contract you want. In the code below, the data contract is defined to have a List<MyData>; if the response contains only one data point, it will "wrap" that into an array prior to passing to the deserializer, so it will work for all cases.
Notice that I used the JSON.NET library to do the JSON modification, but that's not a requirement (it just has a nice JSON DOM to work with the JSON document).
public class StackOverflow_12825062
{
[ServiceContract]
public class Service
{
[WebGet]
public Stream GetData(bool singleDataPoint)
{
string result;
if (singleDataPoint)
{
result = #"{
""Data"":
{
""MyPropertyA"":""Value1"",
""MyPropertyB"":""Value2""
},
}";
}
else
{
result = #"{
""Data"":
[
{
""MyPropertyA"":""Value1"",
""MyPropertyB"":""Value2""
},
{
""MyPropertyA"":""Value3"",
""MyPropertyB"":""Value4""
},
{
""MyPropertyA"":""Value5"",
""MyPropertyB"":""Value6""
}
],
} ";
}
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
}
[DataContract]
public class MyData
{
[DataMember]
public string MyPropertyA { get; set; }
[DataMember]
public string MyPropertyB { get; set; }
}
[DataContract]
public class MyResponse
{
[DataMember]
public List<MyData> Data { get; set; }
public override string ToString()
{
return string.Format("MyResponse, Data.Length={0}", Data.Count);
}
}
[ServiceContract]
public interface ITest
{
[WebGet]
MyResponse GetData(bool singleDataPoint);
}
public class MyResponseSingleOrMultipleClientReplyFormatter : IClientMessageFormatter
{
IClientMessageFormatter original;
public MyResponseSingleOrMultipleClientReplyFormatter(IClientMessageFormatter original)
{
this.original = original;
}
public object DeserializeReply(Message message, object[] parameters)
{
WebBodyFormatMessageProperty messageFormat = (WebBodyFormatMessageProperty)message.Properties[WebBodyFormatMessageProperty.Name];
if (messageFormat.Format == WebContentFormat.Json)
{
MemoryStream ms = new MemoryStream();
XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(ms);
message.WriteMessage(jsonWriter);
jsonWriter.Flush();
string json = Encoding.UTF8.GetString(ms.ToArray());
JObject root = JObject.Parse(json);
JToken data = root["Data"];
if (data != null)
{
if (data.Type == JTokenType.Object)
{
// single case, let's wrap it in an array
root["Data"] = new JArray(data);
}
}
// Now we need to recreate the message
ms = new MemoryStream(Encoding.UTF8.GetBytes(root.ToString(Newtonsoft.Json.Formatting.None)));
XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(ms, XmlDictionaryReaderQuotas.Max);
Message newMessage = Message.CreateMessage(MessageVersion.None, null, jsonReader);
newMessage.Headers.CopyHeadersFrom(message);
newMessage.Properties.CopyProperties(message.Properties);
message = newMessage;
}
return this.original.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw new NotSupportedException("This formatter only supports deserializing reply messages");
}
}
public class MyWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
IClientMessageFormatter result = base.GetReplyClientFormatter(operationDescription, endpoint);
if (operationDescription.Messages[1].Body.ReturnValue.Type == typeof(MyResponse))
{
return new MyResponseSingleOrMultipleClientReplyFormatter(result);
}
else
{
return result;
}
}
}
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");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new WebHttpBinding(), new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new MyWebHttpBehavior());
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.GetData(false));
Console.WriteLine(proxy.GetData(true));
Console.Write("Press ENTER to close the host");
((IClientChannel)proxy).Close();
factory.Close();
Console.ReadLine();
host.Close();
}
}
I don't know about using WCF so I'll change to Asp.Net WCF. Here is an article that will get you one the way
http://www.west-wind.com/weblog/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing
I just can't figure out how to determine if it's an array or a single object. Here is a little code.
[TestMethod]
public void SingleObject()
{
using (var client = new HttpClient())
{
var result = client.GetStringAsync("http://localhost:8080/api/JSONTestOne");
string content = result.Result;
JObject jsonVal = JObject.Parse(content);
dynamic aFooObj = jsonVal;
Console.WriteLine(aFooObj.afoo.A);
}
}
[TestMethod]
public void ArrayWithObject()
{
using (var client = new HttpClient())
{
var result = client.GetStringAsync("http://localhost:8080/api/JSONTest");
string content = result.Result;
JObject jsonVal = JObject.Parse(content);
dynamic foos = jsonVal;
Console.WriteLine(foos[0].A);
}
}