Posting related entities in WCF Rest - wcf

I have developed a sample WCF REST service that accepts that creates an "Order" object, the method implementation is as shown below:
[Description("Updates an existing order")]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, UriTemplate = "/Orders")]
[OperationContract]
public void UpdateOrder(Order order)
{
try
{
using (var context = new ProductsDBEntities())
{
context.Orders.Attach(order);
context.ObjectStateManager.ChangeObjectState(order, System.Data.EntityState.Modified);
context.SaveChanges();
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
WebOperationContext.Current.OutgoingResponse.StatusDescription = "Order updated successfully.";
}
}
catch (Exception ex)
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError;
WebOperationContext.Current.OutgoingResponse.StatusDescription = ex.Message + " " + ((ex.InnerException != null) ? ex.InnerException.Message : string.Empty);
}
}
I am trying to consume this service in a client using the "WCF Rest Starter Kit" assemblies. The client side code to consume the service is as below:
var order = new Order(){
OrderId = Convert.ToInt32(ddlCategories.SelectedItem.Value)
};
order.Order_X_Products.Add(new Order_X_Products { ProductId = 1, Quantity = 10});
order.Order_X_Products.Add(new Order_X_Products { ProductId = 2, Quantity = 10});
var content = HttpContentExtensions.CreateJsonDataContract<Order>(order);
var updateResponse = client.Post("Orders", content);
The below line
var updateResponse = client.Post("Orders", content);
throws the following error:
Server Error in '/' Application.
Specified argument was out of the range of valid values.
Parameter name: value
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: value
I have a similar logic to create an order and its working fine.
I also tried by removing the following lines
order.Order_X_Products.Add(new Order_X_Products { ProductId = 1, Quantity = 10});
order.Order_X_Products.Add(new Order_X_Products { ProductId = 2, Quantity = 10});
but still the same error.
Please help me solve this issue.
I have also tried serializing the Order object to XML and changing the RequestFormat of UpdateOrder method to XML. In this case I am getting the following error, if any related entities are populated.
Server Error in '/' Application.
Object graph for type 'WcfRestSample.Models.Common.Order_X_Products' contains cycles and cannot be serialized if reference tracking is disabled.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Runtime.Serialization.SerializationException: Object graph for type 'WcfRestSample.Models.Common.Order_X_Products' contains cycles and cannot be serialized if reference tracking is disabled.
Source Error:
Line 102:
Line 103: var content = HttpContentExtensions.CreateDataContract<Order> (order);
Line 104: var updateResponse = client.Post("Orders", content);
Line 105:
Line 106:
I want to "Update" an order along with the related "Products" through the "Order_X_Products" mapping table.

There is a post here http://smehrozalam.wordpress.com/2010/10/26/datacontractserializer-working-with-class-inheritence-and-circular-references/ that talks about how to deal with circular references when using the DataContractSerializer.

Related

Swagger UI doesn't support uploading a file properly for RestEasy

I use a JAX-RS (RestEasy) along with a Swagger. One of my endpoint can upload a file. Defined way to upload the file (in RestEasy) is to provide a org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput as a parameter.
Here is my endpoint:
#PUT
#Path("/apis/{id}/file")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Registers a file.", code = 201, nickname = "registerFile")
#ApiResponses(
value = {
#ApiResponse(code = 201, message = "File created.",
response = FileCreated.class),
#ApiResponse(code = 400, message = "Invalid parameters."),
#ApiResponse(code = 404, message = "API is not found.")})
Response registerFile(
#ApiParam(value = "API ID.", required = true) #PathParam("id") String apiId,
#ApiParam(value = "File to register.", required = true, type = "file", name = "apiFile")
MultipartFormDataInput apiFile) throws AppException;
What is the problem?
Unfortunately, swagger-ui generates a schema based on the inner properties of the MultipartFormDataInput instead of a button to upload the file.
I tried use a #FormParam annotation (to indicate that the providing parameter should be interpreted as file) along with the MultipartFormDataInput parameter, but then the app doesn't want to compile.
Question: Is there any solution/workaround to provide the button to upload the file in the swagger-ui?
The solution is removing #ApiParam from your apiFile argument and adding #ApiImplicitParam (which is not bound to Jax-RS and allows defining parameters manually) above the method :
#ApiImplicitParams({#ApiImplicitParam (value = "File to register.", required = true, dataType = "file", name = "apiFile", paramType="formData")})
The final solution
The final solution includes a selected answer, but instead of removing #ApiParam we should add #ApiParam(hidden = true). Why?
If we remove #ApiParam, there are two fields: apiId, body with the inner properties of the MultipartFormDataInput and the button to upload the file in the swagger-ui. This body field is a side effect. To fix this issue we should provide #ApiParam(hidden = true), then there are the field with apiId and the button to upload the file in the swagger-ui.
BTW: I tested below code for swagger-ui in 1.5.12 version.
#PUT
#Path("/apis/{id}/file")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Registers a file.", code = 201, nickname = "registerFile")
#ApiResponses(
value = {
#ApiResponse(code = 201, message = "File created.",
response = FileCreated.class),
#ApiResponse(code = 400, message = "Invalid parameters."),
#ApiResponse(code = 404, message = "API is not found.")})
#ApiImplicitParams(
#ApiImplicitParam(value = "File to register.", required = true, dataType = "file",
name = "apiFile", paramType = "formData"))
Response registerFile(
#ApiParam(value = "API ID.", required = true) #PathParam("id") String apiId,
#ApiParam(hidden = true) MultipartFormDataInput apiFile) throws AppException;

How does ibm - mobile first get mobile number from security context?

I am following "isRegistered" api from this sample code. I did not understand how we get phone number from security context.
The API that I want to use is:
#Path("/isRegistered")
#GET
#Produces("application/json")
#OAuthSecurity(enabled = true)
#ApiOperation(value = "Check if a phone number is registered",
notes = "Check if a phone number is registered",
httpMethod = "GET",
response = Boolean.class
)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK",
response = String.class),
#ApiResponse(code = 401, message = "Not Authorized",
response = String.class),
#ApiResponse(code = 500, message = "Cannot check if phone number is registered",
response = String.class)
})
public Boolean isRegistered() {
//Getting client data from the security context
ClientData clientData = securityContext.getClientRegistrationData();
if (clientData == null) {
throw new InternalServerErrorException("This check allowed only from a mobile device.");
}
String number = clientData.getProtectedAttributes().get(SMSOTPSecurityCheck.PHONE_NUMBER);
return number != null && !number.trim().equals("");
}
How does the security context have the client phone number?
There is a client project as well in this sample. Please refer to the complete sample.
Within the client side logic here, the user is asked to provide the phone number , which is sent to the server in an adapter call:
MainViewController.codeDialog("Phone Number", message: "Please provide your phone number",isCode: true) { (phone, ok) -> Void in
if ok {
let resourseRequest = WLResourceRequest(URL: NSURL(string:"/adapters/smsOtp/phone/register/\(phone)")!, method:"POST")
.....
Now in the adapter code path #Path("/register/{phoneNumber}") notice the following code:
clientData.getProtectedAttributes().put(SMSOTPSecurityCheck.PHONE_NUMBER, phoneNumber);
securityContext.storeClientRegistrationData(clientData);
This is how the phone number made it to the security context.
Run the sample and use a tool such as Wireshark to analyze the data flow between client and server.

SSRS Report executes directly but WCF ReportExporter.Export method returns null Result and no errors

I have a report that is hosted in SQL Server 2012 SSRS and it executes fine through the browser. I am trying to run it using WCF as a Service Reference for the SSRS 2005 asmx from a ASP.Net web project and return it as a PDF using the ReportExporter.Export() method; however, it is not returning a result at all and the warnings array is empty. So, how can I troubleshoot the process to see where the difficulty is? I did not find any errors in the SSRS Log file even when I set it to verbose; nor did I find any errors in the standard SQL Log.
Here is my code:
NOTE: the call ReportExporter.Export(..) is to a method that encapsulates the execution of the webServiceProxy to the Service Reference.
{
IList<SSRS_Reports.ParameterValue> parameters = new List<SSRS_Reports.ParameterValue>();
parameters.Add(new SSRS_Reports.ParameterValue { Name = "paramId", Value = _paramId.ToString() }); }
byte[] result = null;
string extension = string.Empty;
string mimeType = string.Empty;
string encoding = string.Empty;
string reportName = "/baseFolder/ReceiptReport";
SSRS_Reports.Warning[] warnings = null;
string[] streamIDs = null;
string uN = ConfigurationManager.AppSettings["rptUName"].ToString();
string uP = ConfigurationManager.AppSettings["rptPWD"].ToString();
string uD = ConfigurationManager.AppSettings["rptDomain"].ToString();
//NOTE: the call "ReportExporter.Export(..) is to a method that encapsulates the execution of the webServiceProxy to the Service Reference.
ReportExporter.Export("ReportExecutionServiceSoap",
new System.Net.NetworkCredential(uN, uP, uD),
reportName,
parameters.ToArray(),
ExportFormat.PDF,
out result,
out extension,
out mimeType,
out encoding,
out warnings,
out streamIDs);
if (result != null)
{
//create a file and then show in browser
_mPDFFile = randomName() + ".pdf";
_mPDFPath = HttpRuntime.AppDomainAppPath + "\\pdf\\" + _mPDFFile;
//clear files older than today
Lib.FileManager.ManageFiles(HttpRuntime.AppDomainAppPath + "\\pdf", "*.pdf", -1);
if (File.Exists(_mPDFPath))
{
File.Delete(_mPDFPath);
}
FileStream stream = File.Create(_mPDFPath, result.Length);
stream.Write(result, 0, result.Length);
stream.Close();
return true;
}
}

Unable to update unidata from .NET

I've been attempting for the last couple of days to update unidata using sample code as a basis using .NET without success. I can read the database successfully and view the raw data within visual studio. The error reported back is a out of range error. The program is attempting to update the unit price of a purchase order.
Error:
{" Error on Socket Receive. Index was outside the bounds of the array.POD"}
[IBMU2.UODOTNET.UniFileException]: {" Error on Socket Receive. Index was outside the bounds of the array.POD"}
Data: {System.Collections.ListDictionaryInternal}
HelpLink: null
HResult: -2146232832
InnerException: null
Message: " Error on Socket Receive. Index was outside the bounds of the array.POD"
Source: "UniFile Class"
StackTrace: " at IBMU2.UODOTNET.UniFile.Write()\r\n at IBMU2.UODOTNET.UniFile.Write(String aRecordID, UniDynArray aRecordData)\r\n at ReadXlsToUnix.Form1.TestUpdate(String PO_LINE_SHIP, String price) in c:\Users\xxx\Documents\Visual Studio 2013\Projects\ReadXlsToUnix\ReadXlsToUnix\Form1.cs:line 330"
TargetSite: {Void Write()}
failing Test Code is:
private void TestUpdate(string PO_LINE_SHIP,string price)
{
UniFile pod =null;
UniSession uniSession =null;
//connection string
uniSession = UniObjects.OpenSession("unixMachine", "userid", Properties.Settings.Default.PWD, "TRAIN", "udcs");
//open file
pod = uniSession.CreateUniFile("POD");
//read data
pod.Read(PO_LINE_SHIP);
//locking strategy
pod.UniFileLockStrategy = 1;
pod.UniFileReleaseStrategy = 1;
if (pod.RecordID == ""){
pod.UnlockRecord();
}
//replace existing value with one entered by user
pod.Record.Replace(4, (string)uniSession.Iconv(price, "MD4"));
try
{
pod.Write(pod.RecordID,pod.Record); //RecordId and Record both show correctly hover/immediate window
//pod.Write() fails with same message
}
catch (Exception err)
{
MessageBox.Show("Error" + err);
}
pod.Close();
UniObjects.CloseSession(uniSession);
}
}
Running on HP UX 11.31 unidata 7.2 and using UODOTNET.dll 2.2.3.7377
Any help greatly appreciated.
This is the write record version and have also tried writefield functionality with same error.
Rajan - thanks for the update and link. I have tried unsuccessfully to read/update my unidata tables using the U2 Toolkit. I can however read/update a file I have created within the same account. Does this mean there is a missing entry somewhere VOC, DICT for example.

VTD-XML Exception: Name space qualification Exception: prefixed attribute not qualified

I receive an XML via a web service and I am using legacy code (which uses dom4j) to perform some xml transformation. Loading/parsing the original XML into VTD-XML (VTDGen) works fine, no exceptions thrown. However, after loading the xml into dom4j, I noticed some of the element namespace declarations and attributes are re-arranged. Apparently, this re-arrangement causes VTD-XML to throw the following exception:
Exception:
Name space qualification Exception: prefixed attribute not qualified
Line Number: 101 Offset: 1827
Here is the element at this line number in the original XML:
<RR_PerformanceSite:PerformanceSite_1_4 RR_PerformanceSite:FormVersion="1.4" xmlns:NSF_ApplicationChecklist="http://apply.grants.gov/forms/NSF_ApplicationChecklist-V1.1" xmlns:NSF_CoverPage="http://apply.grants.gov/forms/NSF_CoverPage-V1.1" xmlns:NSF_DeviationAuthorization="http://apply.grants.gov/forms/NSF_DeviationAuthorization-V1.1" xmlns:NSF_Registration="http://apply.grants.gov/forms/NSF_Registration-V1.1" xmlns:NSF_SuggestedReviewers="http://apply.grants.gov/forms/NSF_SuggestedReviewers-V1.1" xmlns:PHS398_CareerDevelopmentAwardSup="http://apply.grants.gov/forms/PHS398_CareerDevelopmentAwardSup_1_1-V1.1" xmlns:PHS398_Checklist="http://apply.grants.gov/forms/PHS398_Checklist_1_3-V1.3" xmlns:PHS398_CoverPageSupplement="http://apply.grants.gov/forms/PHS398_CoverPageSupplement_1_4-V1.4" xmlns:PHS398_ModularBudget="http://apply.grants.gov/forms/PHS398_ModularBudget-V1.1" xmlns:PHS398_ResearchPlan="http://apply.grants.gov/forms/PHS398_ResearchPlan_1_3-V1.3" xmlns:PHS_CoverLetter="http://apply.grants.gov/forms/PHS_CoverLetter_1_2-V1.2" xmlns:RR_Budget="http://apply.grants.gov/forms/RR_Budget-V1.1" xmlns:RR_KeyPersonExpanded="http://apply.grants.gov/forms/RR_KeyPersonExpanded_1_2-V1.2" xmlns:RR_OtherProjectInfo="http://apply.grants.gov/forms/RR_OtherProjectInfo_1_2-V1.2" xmlns:RR_PerformanceSite="http://apply.grants.gov/forms/PerformanceSite_1_4-V1.4" xmlns:RR_PersonalData="http://apply.grants.gov/forms/RR_PersonalData-V1.1" xmlns:RR_SF424="http://apply.grants.gov/forms/RR_SF424_1_2-V1.2" xmlns:RR_SubawardBudget="http://apply.grants.gov/forms/RR_SubawardBudget-V1.2" xmlns:SF424C="http://apply.grants.gov/forms/SF424C-V1.0" xmlns:att="http://apply.grants.gov/system/Attachments-V1.0" xmlns:codes="http://apply.grants.gov/system/UniversalCodes-V2.0" xmlns:globlib="http://apply.grants.gov/system/GlobalLibrary-V2.0">
Here is the same element after loaded into dom4j:
<RR_PerformanceSite:PerformanceSite_1_4 xmlns:RR_PerformanceSite="http://apply.grants.gov/forms/PerformanceSite_1_4-V1.4" xmlns:NSF_ApplicationChecklist="http://apply.grants.gov/forms/NSF_ApplicationChecklist-V1.1" xmlns:NSF_CoverPage="http://apply.grants.gov/forms/NSF_CoverPage-V1.1" xmlns:NSF_DeviationAuthorization="http://apply.grants.gov/forms/NSF_DeviationAuthorization-V1.1" xmlns:NSF_Registration="http://apply.grants.gov/forms/NSF_Registration-V1.1" xmlns:NSF_SuggestedReviewers="http://apply.grants.gov/forms/NSF_SuggestedReviewers-V1.1" xmlns:PHS398_CareerDevelopmentAwardSup="http://apply.grants.gov/forms/PHS398_CareerDevelopmentAwardSup_1_1-V1.1" xmlns:PHS398_Checklist="http://apply.grants.gov/forms/PHS398_Checklist_1_3-V1.3" xmlns:PHS398_CoverPageSupplement="http://apply.grants.gov/forms/PHS398_CoverPageSupplement_1_4-V1.4" xmlns:PHS398_ModularBudget="http://apply.grants.gov/forms/PHS398_ModularBudget-V1.1" xmlns:PHS398_ResearchPlan="http://apply.grants.gov/forms/PHS398_ResearchPlan_1_3-V1.3" xmlns:PHS_CoverLetter="http://apply.grants.gov/forms/PHS_CoverLetter_1_2-V1.2" xmlns:RR_Budget="http://apply.grants.gov/forms/RR_Budget-V1.1" xmlns:RR_KeyPersonExpanded="http://apply.grants.gov/forms/RR_KeyPersonExpanded_1_2-V1.2" xmlns:RR_OtherProjectInfo="http://apply.grants.gov/forms/RR_OtherProjectInfo_1_2-V1.2" xmlns:RR_PersonalData="http://apply.grants.gov/forms/RR_PersonalData-V1.1" xmlns:RR_SF424="http://apply.grants.gov/forms/RR_SF424_1_2-V1.2" xmlns:RR_SubawardBudget="http://apply.grants.gov/forms/RR_SubawardBudget-V1.2" xmlns:SF424C="http://apply.grants.gov/forms/SF424C-V1.0" xmlns:att="http://apply.grants.gov/system/Attachments-V1.0" xmlns:codes="http://apply.grants.gov/system/UniversalCodes-V2.0" xmlns:globlib="http://apply.grants.gov/system/GlobalLibrary-V2.0" RR_PerformanceSite:FormVersion="1.4">
The problem is regarding the attribute (at offset 1827, at the end of the element) in the new XML element: RR_PerformanceSite:FormVersion="1.4"
Here is what removes the exception:
1. Adding the RR_PerformanceSite xmlns declaration for this element to the root element of the XML doc.
2. Replacing new element with original element. This SEEMS to lead me to believe that the order of the attributes/ns declarations affects VTD when parsing.
NOTE: I parse the xml doc setting ns aware to 'true' with both xml docs (original and post-dom4j xml). Also, new VTD objects are created for each xml, original and post-dom4j.
I tried to put 'RR_PerformanceSite:FormVersion="1.4"' at the beginning of the element like the original but that does not remove the exception. The offset in the error message is different due to the change of location of the attribute. Does the order of the xmlns declarations affect VTD?
I have looked at the VTDGen source code and cannot figure out why this exception is being thrown.
Why would dom4j parse the new doc and vtd is unable to? Can anyone can shed some light on this?
It appears to be a bug on VTD-XML, related with namespace declaration order.
Always reproducible using the following Java code
public class SchemaTester {
/**
* #param args
*/
public static void main(String[] args) throws Exception {
String bad = "C:/Temp/VTD_bad.xml"; // XML files to test
String good = "C:/Temp/VTD_good.xml";
StringBuilder sb = new StringBuilder();
char[] buf = new char[4*1024];
FileReader fr = new FileReader(bad);
int readed = 0;
while ((readed = fr.read(buf, 0, buf.length)) != -1) {
sb.append(buf, 0, readed);
}
fr.close();
String x = sb.toString();
//instantiate VTDGen
//and call parse
VTDGen vg = new VTDGen();
vg.setDoc(x.getBytes("UTF-8"));
vg.parse(true); // set namespace awareness to true
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot (vn);
ap.selectXPath("//*/#*");
int i= -1;
while((i=ap.evalXPath()) != -1) {
// i will be attr name, i+1 will be attribute value
System.out.println("\t\tAttribute ==> " + vn.toNormalizedString(i));
System.out.println("\t\tValue ==> " + vn.toNormalizedString(i+1));
}
}
}
The OP has uploaded the XML to https://gist.github.com/2696220