Element is not an instance of type - msmq

I am using Linq To XSD to send data over MSMQ. Here is my sending code
public void Send()
{
string criMessageQueuePath = ConfigurationManager.AppSettings["CRIMessageQueuePath"];
if (!MessageQueue.Exists(criMessageQueuePath))
{
MessageQueue.Create(criMessageQueuePath, false);
}
var messageQueue = new MessageQueue(criMessageQueuePath) { Label = "CRI Message Queue" };
messageQueue.Formatter = new XmlMessageFormatter(new[] { typeof(XML) });
var transaction = new MessageQueueTransaction();
transaction.Begin();
messageQueue.Send(CreateAuction(1), transaction);
messageQueue.Send(CreateAuction(2), transaction);
messageQueue.Send(CreateAuction(3), transaction);
messageQueue.Send(CreateAuction(4), transaction);
messageQueue.Send(CreateAuction(5), transaction);
transaction.Commit();
}
private XML CreateAuction(int id)
{
var message = new XML {id = id};
return message;
}
Here is my receiving code
public IEnumerable<string> Receive()
{
string criMessageQueuePath = ConfigurationManager.AppSettings["CRIMessageQueuePath"];
var messageQueue = new MessageQueue(criMessageQueuePath);
Message[] messages = messageQueue.GetAllMessages();
foreach (Message message in messages)
{
message.Formatter = new XmlMessageFormatter(new[] { typeof(XML) });
yield return message.Body.ToString();
}
messageQueue.Purge();
}
I've tried lots of variations of this code but can't figure out why I can't get a valid XML object out the other end.
Currently, my code is failing when I call it
static void Main()
{
var sender = new Sender.Sender();
sender.Send();
var receiver = new Receiver.Receiver();
foreach (var xml in receiver.Receive())
{
var typedXML = XML.Parse(xml);
Console.WriteLine(typedXML.id);
}
}
The line it fails on is var typedXML = XML.Parse(xml);. The error is
Element is not an instance of type Domain.XML
The XSD for the object is
<?xml version="1.0" encoding="Windows-1252"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="Domain">
<xs:element name="XML">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Looking at the value of xml on the line
var typedXML = XML.Parse(xml);
I can see that it generates this
"<XML>\r\n <XML xmlns=\"Domain\">\r\n <id>1</id>\r\n </XML>\r\n</XML>"
In other words it generates an additional xml node around the whole xml. If I remove this extra node in the debugger then it all works. what am I doing wrong?

This is the result of using hte XmlMessageFormatter as it serializes your object and wraps it in XML. I would suggest that you write your XML document directly to the BodyStream property instead.
var msg = new Message();
var writer = new StreamWriter(msg.BodyStream);
writer.Write(xmlDoc.ToString());
writer.Flush();
queue.Send(msg);
This way you have full Control over what is sent in your queue. The formatters are mostly there for legacy use and should not be used when sending XML documents as messages.

Related

Get base64 data of file from Salesforce

I need to get opportunity files from Salesforce and copy them to some folder. I am using .NET library for connecting to Salesforcre. I can get any data I want, except the [VersionData] field in [ContentVersion] table, which contains base64 data of the files I want. I can get the data with Workbench tool, but the only thing I get via .NET library is a link to file. I could create HttpClient with appropriate headers and invoke that URL, but I don't like to go this ways. Can I get the file via .NET library?
In REST API it has to be pulled through that url you got. It'll be a raw binary stream of data which would be tricky to represent together within JSON of normal query results. REST API is focused on mobile apps, minimizing network usage and base64 decode is some processing power I guess.
It shouldn't be tricky though? Just a GET to the URL you got with header Authorization: Bearer <session id here>
If you want base64 you need to make it a SOAP API request (which is what Workbench really uses, note that "REST explorer" is a separate menu option).
POST request to https://<redacted>.my.salesforce.com/services/Soap/u/48.0
with payload like
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com">
<soapenv:Header>
<urn:SessionHeader>
<urn:sessionId>nice try ;) you can reuse same session id</urn:sessionId>
</urn:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<urn:query>
<urn:queryString>SELECT VersionData FROM ContentVersion WHERE Id = '068...'</urn:queryString>
</urn:query>
</soapenv:Body>
</soapenv:Envelope>
Will give you something like this back
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sf="urn:sobject.partner.soap.sforce.com">
<soapenv:Header>
<LimitInfoHeader>
<limitInfo>
<current>12</current>
<limit>5000000</limit>
<type>API REQUESTS</type>
</limitInfo>
</LimitInfoHeader>
</soapenv:Header>
<soapenv:Body>
<queryResponse>
<result xsi:type="QueryResult">
<done>true</done>
<queryLocator xsi:nil="true"/>
<records xsi:type="sf:sObject">
<sf:type>ContentVersion</sf:type>
<sf:Id xsi:nil="true"/>
<sf:VersionData>/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/
(bla bla bla)
/X/lf0eG9Kl61//Z</sf:VersionData>
</records>
<size>1</size>
</result>
</queryResponse>
</soapenv:Body>
</soapenv:Envelope>
I was struggling with the same issue using the Force.com Toolkit for .NET and didn't want to switch to a workaround (for example doing a separate SOAP call or implement my own HttpClient).
So I found out it is actually natively supported using the Toolkit. I didn't found it anywhere in the documentation (which is not extensive anyway), so I post it here, maybe it will help some other developers.
Console.WriteLine($"ContentDocumentLink ID: {contentDocumentLink.Id}");
Console.WriteLine($"ContentDocument ID: {contentDocumentLink.ContentDocumentId}");
// Get ContentDocument record
var contentDocument = await client.QueryByIdAsync<ContentDocument>("ContentDocument", contentDocumentLink.ContentDocumentId);
Console.WriteLine($"ContentVersion ID: {contentDocument.LatestPublishedVersionId}");
// Get ContentVersion record
var contentVersion = await client.QueryByIdAsync<ContentVersion>("ContentVersion", contentDocument.LatestPublishedVersionId);
// convert Bytes to KiloBytes presentation
string fullFileName = $"{contentVersion.Title}.{contentVersion.FileExtension}";
int FileSizeInBytes = contentVersion.ContentSize;
int FileSizeInKiloBytes = (int)ByteSize.FromBytes(FileSizeInBytes).LargestWholeNumberBinaryValue;
Console.WriteLine($"Filename: {fullFileName} ({FileSizeInKiloBytes} KB)");
// Get VersionData as a stream
var versionData = await client.GetBlobAsync("ContentVersion", contentDocument.LatestPublishedVersionId, "VersionData");
var fileStream = File.Create($"C:\\Temp\\{contentVersion.Title}.{contentVersion.FileExtension}");
versionData.CopyTo(fileStream);
fileStream.Close();
So the trick is using the GetBlobAsync method on base64 fields in SalesForce.
This will initiate a GET request on the desired endpoint: '/services/data/v49.0/sobjects/ContentVersion/<ContentVersion_ID>/VersionData'.
And the response will be a 'Content-Type: application/octetstream' one captured into a Stream.
Here is my solution (model class, endpoint method, authentication method):
public class ContentVersion
{
[JsonIgnoreSerialization]
[JsonProperty("Id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }
[JsonProperty("ContentDocumentId")]
public string ContentDocumentId { get; set; }
[JsonProperty("FileExtension")]
public string FileExtension { get; set; }
[JsonProperty("Title")]
public string Title { get; set; }
[JsonProperty("VersionNumber")]
public int VersionNumber { get; set; }
[JsonProperty("IsLatest")]
public bool IsLatest { get; set; }
[JsonProperty("VersionData")]
public string VersionDataURL { get; set; }
public Stream VersionDataStream { get; set; }
}
public async Threading.Task<ContentVersion> GetContentNewestVersion(string EntityId)
{
// Authenticate if not already
if (client == null) await Authenticate();
// Create query string
string query = #"SELECT
Id,
ContentDocumentId,
FileExtension,
Title,
VersionNumber,
IsLatest,
VersionData
FROM ContentVersion
WHERE ContentDocumentId = '" + EntityId + "'";
List<ContentVersion> results = new List<ContentVersion>();
QueryResult<ContentVersion> queryResult = await client.QueryAsync<ContentVersion>(query);
results.AddRange(queryResult.Records);
while (!queryResult.Done)
{
queryResult = await client.QueryContinuationAsync<ContentVersion>(queryResult.NextRecordsUrl);
results.AddRange(queryResult.Records);
}
// get only the newest Content version
ContentVersion latestContentVersion = results.Where(r => r.IsLatest).OrderByDescending(r => r.VersionNumber).FirstOrDefault();
// Get file stream via returned URL
using (HttpClient httpClient = new HttpClient())
{
// Add access token to request
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", AccessToken);
// call server
var response = await httpClient.GetAsync(InstanceUrl + latestContentVersion.VersionDataURL);
// read stream and append it to object
latestContentVersion.VersionDataStream = await response.Content.ReadAsStreamAsync();
}
return latestContentVersion;
}
protected async Threading.Task Authenticate()
{
// Check if not already connected
if (client == null)
{
// Security settings
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Create Auth client
var auth = new AuthenticationClient();
// Authorize user
await auth.UsernamePasswordAsync(LoginDetails.ClientId, LoginDetails.ClientSecret, LoginDetails.Username, LoginDetails.Password, LoginDetails.TokenRequestEndpoint);
_instanceURL = auth.InstanceUrl;
AccessToken = auth.AccessToken;
// Create and return client with session variables
client = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
}
And this is how I write recieved stream to file.
// deisred folder
string PathToFolder = #"C:\destination\";
// get stream from Salesforce
ContentVersion documentContent = await forceAPI.GetContentNewestVersion(contentDocumentlink.ContentDocumentId);
// write file from stream
using (FileStream file = new FileStream(PathToFolder + documentContent.Title + "." + documentContent.FileExtension, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
documentContent.VersionDataStream.CopyTo(file);
}

Native Client - Serialization Exception when executing Continuous Query

I'm trying to set up a simple Java <-> #C/.NET proof of concept using Apache Geode, specifically testing the continuous query functionality using the .NET native client. Using a regular Query works fine from .NET, only the Continuous Query has an issue. I run into my problem when I call the Execute() method on the continuous query object. The specific error I get is
Got unhandled message type 26 while processing response, possible serialization mismatch
I'm only storing simple strings in the cache region so I'm a bit surprised that I'm having serialization issues. I've tried enabling PDX serialization on both sides (and running without it), it doesn't seem to make a difference. Any ideas?
Here is my code for both sides:
Java
Starts a server, puts some data, and then keeps updating a given cache entry.
public class GeodePoc {
public static void main(String[] args) throws Exception {
ServerLauncher serverLauncher = new ServerLauncher.Builder().setMemberName("server1")
.setServerBindAddress("localhost").setServerPort(10334).set("start-locator", "localhost[20341]")
.set(ConfigurationProperties.LOG_LEVEL, "trace")
.setPdxReadSerialized(true)
.set(ConfigurationProperties.CACHE_XML_FILE, "cache.xml").build();
serverLauncher.start();
Cache c = CacheFactory.getAnyInstance();
Region<String, String> r = c.getRegion("example_region");
r.put("test1", "value1");
r.put("test2", "value2");
System.out.println("Cache server successfully started");
int i = 0;
while (true) {
r.put("test1", "value" + i);
System.out.println(r.get("test1"));
Thread.sleep(3000);
i++;
}
}
}
Server cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
version="1.0">
<cache-server bind-address="localhost" port="40404"
max-connections="100" />
<pdx>
<pdx-serializer>
<class-name>org.apache.geode.pdx.ReflectionBasedAutoSerializer</class-name>
<parameter name="classes">
<string>java.lang.String</string>
</parameter>
</pdx-serializer>
</pdx>
<region name="example_region">
<region-attributes refid="REPLICATE" />
</region>
</cache>
.NET Client
public static void GeodeTest()
{
Properties<string, string> props = Properties<string, string>.Create();
props.Insert("cache-xml-file", "<path-to-cache.xml>");
CacheFactory cacheFactory = new CacheFactory(props)
.SetPdxReadSerialized(true).SetPdxIgnoreUnreadFields(true)
.Set("log-level", "info");
Cache cache = cacheFactory.Create();
cache.TypeRegistry.PdxSerializer = new ReflectionBasedAutoSerializer();
IRegion<string, string> region = cache.GetRegion<string, string>("example_region");
Console.WriteLine(region.Get("test2", null));
PoolManager pManager = cache.GetPoolManager();
Pool pool = pManager.Find("serverPool");
QueryService qs = pool.GetQueryService();
// Regular query example (works)
Query<string> q = qs.NewQuery<string>("select * from /example_region");
ISelectResults<string> results = q.Execute();
Console.WriteLine("Finished query");
foreach (string result in results)
{
Console.WriteLine(result);
}
// Continuous Query (does not work)
CqAttributesFactory<string, object> cqAttribsFactory = new CqAttributesFactory<string, object>();
ICqListener<string, object> listener = new CacheListener<string, object>();
cqAttribsFactory.InitCqListeners(new ICqListener<string, object>[] { listener });
cqAttribsFactory.AddCqListener(listener);
CqAttributes<string, object> cqAttribs = cqAttribsFactory.Create();
CqQuery<string, object> cquery = qs.NewCq<string, object>("select * from /example_region", cqAttribs, false);
Console.WriteLine(cquery.GetState());
Console.WriteLine(cquery.QueryString);
Console.WriteLine(">>> Cache query example started.");
cquery.Execute();
Console.WriteLine();
Console.WriteLine(">>> Example finished, press any key to exit ...");
Console.ReadKey();
}
.NET Cache Listener
public class CacheListener<TKey, TResult> : ICqListener<TKey, TResult>
{
public virtual void OnEvent(CqEvent<TKey, TResult> ev)
{
object val = ev.getNewValue() as object;
TKey key = ev.getKey();
CqOperation opType = ev.getQueryOperation();
string opStr = "DESTROY";
if (opType == CqOperation.OP_TYPE_CREATE)
opStr = "CREATE";
else if (opType == CqOperation.OP_TYPE_UPDATE)
opStr = "UPDATE";
Console.WriteLine("MyCqListener::OnEvent called with key {0}, op {1}.", key, opStr);
}
public virtual void OnError(CqEvent<TKey, TResult> ev)
{
Console.WriteLine("MyCqListener::OnError called");
}
public virtual void Close()
{
Console.WriteLine("MyCqListener::close called");
}
}
.NET Client cache.xml
<client-cache
xmlns="http://geode.apache.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
version="1.0">
<pool name="serverPool" subscription-enabled="true">
<locator host="localhost" port="20341"/>
</pool>
<region name="example_region">
<region-attributes refid="CACHING_PROXY" pool-name="serverPool" />
</region>
</client-cache>
This ended up being a simple oversight on my part. In order for continuous query to function you must include the geode-cq dependency on the Java side. I didn't do this, and this caused the exception.

Camel mongodb - MongoDbProducer multiple inserts

I am trying to do a multiple insert using the camel mongo db component.
My Pojo representation is :
Person {
String firstName;
String lastName;
}
I have a processor which constructs a valid List of Person pojo and is a valid json structure.
When this list of Person is sent to the mongodb producer , on invocation of createDoInsert the type conversion to BasicDBObject fails. This piece of code below looks to be the problem. Should it have more fall backs / checks in place to attempt the list conversion down further below as it fails on the very first cast itself. Debugging the MongoDbProducer the exchange object being received is a DBList which extends DBObject. This causes the singleInsert flag to remain set at true which fails the insertion below as we get a DBList instead of a BasicDBObject :
if(singleInsert) {
BasicDBObject insertObjects = (BasicDBObject)insert;
dbCol.insertOne(insertObjects);
exchange1.getIn().setHeader("CamelMongoOid", insertObjects.get("_id"));
}
The Camel MongoDbProducer code fragment
private Function<Exchange, Object> createDoInsert() {
return (exchange1) -> {
MongoCollection dbCol = this.calculateCollection(exchange1);
boolean singleInsert = true;
Object insert = exchange1.getIn().getBody(DBObject.class);
if(insert == null) {
insert = exchange1.getIn().getBody(List.class);
if(insert == null) {
throw new CamelMongoDbException("MongoDB operation = insert, Body is not conversible to type DBObject nor List<DBObject>");
}
singleInsert = false;
insert = this.attemptConvertToList((List)insert, exchange1);
}
if(singleInsert) {
BasicDBObject insertObjects = (BasicDBObject)insert;
dbCol.insertOne(insertObjects);
exchange1.getIn().setHeader("CamelMongoOid", insertObjects.get("_id"));
} else {
List insertObjects1 = (List)insert;
dbCol.insertMany(insertObjects1);
ArrayList objectIdentification = new ArrayList(insertObjects1.size());
objectIdentification.addAll((Collection)insertObjects1.stream().map((insertObject) -> {
return insertObject.get("_id");
}).collect(Collectors.toList()));
exchange1.getIn().setHeader("CamelMongoOid", objectIdentification);
}
return insert;
};
}
My route is as below :
<route id="uploadFile">
<from uri="jetty://http://0.0.0.0:9886/test"/>
<process ref="fileProcessor"/>
<unmarshal>
<csv>
<header>fname</header>
<header>lname</header>
</csv>
</unmarshal>
<process ref="mongodbProcessor" />
<to uri="mongodb:mongoBean?database=axs175&collection=insurance&operation=insert" />
and the MongoDBProcessor constructing the List of Person Pojo
#Component
public class MongodbProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
ArrayList<List<String>> personlist = (ArrayList) exchange.getIn().getBody();
ArrayList<Person> persons = new ArrayList<>();
for(List<String> records : personlist){
Person person = new Person();
person.setFname(records.get(0));
person.setLname(records.get(1));
persons.add(person);
}
exchange.getIn().setBody(persons);
}
}
Also requested information here - http://camel.465427.n5.nabble.com/Problems-with-MongoDbProducer-multiple-inserts-tc5792644.html
This issue is now fixed via - https://issues.apache.org/jira/browse/CAMEL-10728

JAX-WS client, incorrect soap request - The markup in the document following the root element must be well-formed

I have generated a web service client using wsimport command line (JAX-WS) and generated Java objects using JAXB and separate XSD files.
But when I try to request, it gives following error from server side.
SAXException, cause: The markup in the document following the root element must be well-formed.
So I checked my soap request with a sample working soap message. Then I realized that there is a different between these two messages.
1. Sample working message.
<m:getMyDetail xmlns:m="http://axis.frontend.hi.example.net">
<MyDetailRQ xmlns="http://www.example.net/schemas/1005/06/messages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.net/1005/06/messages ../xsd/MyDetailRQ.xsd"
version="2013/12">
2. Web service client generated soap message.
<ns3:getMyDetail xmlns:ns3="http://axis.frontend.hi.example.net" xmlns="http://www.
example.net/schemas/1005/06/messages" xmlns:ns2="http://www. example.net/wsdl/1005/06"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="MyDetailRQ">
As you can see, above expected MyDetailRQ wrapper tag element is missing but it generated as xsi:type="MyDetailRQ" attribute.
I’m not sure why this happen and how to fix this through my client project configurations.
Appreciate your help and advice.
Thanks
- Relevant WSDL part
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://axis.frontend.h1.example.com">
<element name="getMyDetail" type="xsd:anyType"/>
</schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/wsdl/2005/06">
<element name="getMyDetailReturn" type="xsd:anyType"/>
</schema>
</wsdl:types>
<wsdl:message name="getMyDetailRequest">
<wsdl:part element="tns1:getMyDetail" name="part"/>
</wsdl:message>
<wsdl:message name="getMyDetailResponse">
<wsdl:part element="impl:getMyDetailReturn" name="getMyDetailReturn"/>
</wsdl:message>
<wsdl:portType name="MyService">
<wsdl:operation name="getMyDetail">
<wsdl:input message="impl:getMyDetailRequest" name="getMyDetailRequest"/>
<wsdl:output message="impl:getMyDetailResponse" name="getMyDetailResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MyServiceSoapBinding" type="impl:MyService">
<wsdl:operation name="getMyDetail">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getMyDetailRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getMyDetailResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MyServiceService">
<wsdl:port binding="impl:MyServiceSoapBinding" name="MyService">
<wsdlsoap:address location="http://interface.example.com/xmls/ws/MyService"/>
</wsdl:port>
</wsdl:service>
- Relevant XSD part
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.example.net/schemas/1005/06/messages" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.net/schemas/1005/06/messages" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="MyCommonTypes.xsd"/>
<xs:element name="MyDetailRQ">
- Relevant Java Object
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MyDetailRQ", propOrder = {
"myCode"
})
#XmlRootElement(name = "MyDetailRQ")
public class MyDetailRQ
extends MainRequest
{
}
- web service client - service interface (Updated on 17-Oct-2014)
#WebService(name = "MyService", targetNamespace = "http://www.example.net/wsdl/1005/06")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
#XmlSeeAlso({
com.myp.hi.frontend.axis.ObjectFactory.class,
com.myp.ObjectFactory.class
})
public interface MyService {
/**
*
* #param part
* #return
* returns java.lang.Object
*/
#WebMethod
#WebResult(name = "getMyDetailReturn", targetNamespace = "http://www.example.net/wsdl/1005/06", partName = "getMyDetailReturn")
public Object getMyDetail(
#WebParam(name = "getMyDetail", targetNamespace = "http://axis.frontend.hi.example.net", partName = "part")
Object part);
}
- ObjectFactory class (Updated on 17-Oct-2014)
#XmlRegistry
public class ObjectFactory {
private final static QName _GetMyDetail_QNAME = new QName("http://axis.frontend.hi.example.net", "getMyDetail");
public ObjectFactory() {
}
#XmlElementDecl(namespace = "http://axis.frontend.hi.example.net", name = "getMyDetail")
public JAXBElement<Object> createGetMyDetail(Object value) {
return new JAXBElement<Object>(_GetMyDetail_QNAME, Object.class, null, value);
}
}
-MyServiceService class (Updated on 17-Oct-2014)
#WebServiceClient(name = "MyServiceService", targetNamespace = "http://www.example.net/wsdl/1005/06", wsdlLocation = "http://interface.example.com/xmls/ws/MyService?wsdl")
#GZIP
public class MyServiceService
extends Service
{
private final static URL MYSERVICESERVICE_WSDL_LOCATION;
private final static WebServiceException MYSERVICESERVICE_EXCEPTION;
private final static QName MYSERVICESERVICE_QNAME = new QName("http://www.example.net/wsdl/1005/06", "MyServiceService");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("http://interface.example.com/xmls/ws/MyService?wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
MYSERVICESERVICE_WSDL_LOCATION = url;
MYSERVICESERVICE_EXCEPTION = e;
}
#WebEndpoint(name = "MyService")
public MyService getMyService() {
MyService port = super.getPort(new QName("http://www.example.net/wsdl/1005/06", "MyService"), MyService.class);
return port;
}
private static URL __getWsdlLocation() {
if (MYSERVICESERVICE_EXCEPTION!= null) {
throw MYSERVICESERVICE_EXCEPTION;
}
return MYSERVICESERVICE_WSDL_LOCATION;
}
}
- My Test class (Updated on 17-Oct-2014)
MyService myService = new MyServiceService().getMyService();
MyDetailRQ myDetailRQ = new MyDetailRQ();
myDetailRQ.setCredentials(credentials);
myDetailRQ.setLanguage("ENG");
myDetailRQ.setMyCode("52319");
MyDetailRS myDetailRS = (MyDetailRS) myService.getMyDetail(myService);
I have found a solution, but not sure whether perfect one.
What I have done is; pass a XML String to service and get response as a String from service.
Then manually do marshalling and un- marshalling.
See the example below.
MyService myService = new MyServiceService().getMyService();
MyDetailRQ myDetailRQ = new MyDetailRQ();
myDetailRQ.setCredentials(credentials);
myDetailRQ.setLanguage("ENG");
myDetailRQ.setMyCode("52319");
String requestStr = getStringFromJaxb(myDetailRQ.class, myDetailRQ);
String responseStr = (String) myService.getMyDetail(requestStr);
MyDetailRS myDetailRS = (MyDetailRS) getJaxbFromString(MyDetailRS.class, responseStr);
private static Object getJaxbFromString(Class<?> clazz, String xmlString) {
StringReader input = null;
Object o = null;
try {
input = new StringReader(xmlString);
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller um = context.createUnmarshaller();
o = um.unmarshal(input);
if (o instanceof JAXBElement)
o = ((JAXBElement<?>) o).getValue();
} catch (JAXBException e) {
e.printStackTrace();
} finally {
if (input != null)
input.close();
}
return o;
}
/**
* Helper method to get xml string from JAXB Object.
* #param clazz
* #param o
* #return
*/
private static String getStringFromJaxb(Class<?> clazz, Object o) {
String theXML = "";
try {
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(clazz);
Marshaller m = context.createMarshaller();
m.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
m.marshal(o, writer);
// output string to console
theXML = writer.toString();
} catch (Exception e) {
e.printStackTrace();
}
return theXML;
}

ObjectDatasource passing parameters

I want to Insert data from textboxes using ObjectDatasource. The ObjectDataSource is bound to a gridview but displays certain computed columns only. The Textboxes are used to input all the basic inputs.
ObjectDatasource Delete & Select commands (Link buttons on gridview) are working. However I am having trouble with Insert command. I am not able to figure out how to pass the data from the textboxes as parameters to the ObjectDataSource Insert
EDIT: With the code below, a record is getting inserted. Parameters are getting passed. odssMain.Insert() gives the Error: "Object reference not set to an instance of an object".
EDIT: WHY AM I GETTING THIS ERROR?
Also the ObjectDataSource has been acting weird. After an error, I have to reconfigure the Insert Method again on the ODS Wizard as the method will be blank.
ASP.NET 3.5 & SQL 2008, VS 2008.
Here's my code:
<asp:ObjectDataSource ID="odsMain" runat="server"
SelectMethod="SelectMain" DeleteMethod="DeleteMain"
InsertMethod="InsertMain" UpdateMethod="UpdateMain"
OldValuesParameterFormatString="original_{0}" TypeName="MainDB" >
.......
<InsertParameters>
<asp:Parameter Name="Quantity" Type="Int32" />
</InsertParameters>
DAL FILE:
[DataObjectMethod(DataObjectMethodType.Insert)]
public static int InsertMain(int Quantity)/
{
SqlConnection con = new SqlConnection(GetConnectionString());
string strQuery = "INSERT INTO t_Main (Quantity) VALUES (#Quantity)";
SqlCommand cmd = new SqlCommand(strQuery, con);
cmd.Parameters.AddWithValue("#Quantity", Quantity);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
return i;
}
CODE BEHIND FILE:
protected void btnSaveAnalysis_Click(object sender, EventArgs e)
{
odsMain.InsertParameters.Clear();
//Store parameters with values to the collection
odsMain.InsertParameters.Add(new Parameter ("Quantity", TypeCode.Int32, iQuantity.ToString()));
//Diferent ways that I tried. Still not working
//odsMain.InsertParameters.Add("Quantity", iQuantity.ToString());
//odsMain.InsertParameters["Quantity"].DefaultValue = iQuantity.ToString();
odsMain.Insert();
}
you could try like this....
ObjectDataSource for InsertParameter looks like below one
<InsertParameters>
<asp:Parameter Name="FirstName" />
<asp:Parameter Name="MiddleName" />
<asp:Parameter Name="LastName" />
<asp:Parameter Name="Desgination" />
<asp:Parameter Name="Address" />
<asp:Parameter Name="City" />
<asp:Parameter Name="State" />
<asp:Parameter Name="Country" />
</InsertParameters>
I will also pass InsertMethod property of ObjectDataSource,which will have an InsertCustomer method.
InsertCustomer method looks like below one :-
public void InsertCustomer(string FirstName, string MiddleName,string LastName, string Desgination, string Address, string City, string State, string Country)
{
SqlConnection con = new SqlConnection(conStr);
SqlCommand cmd = new SqlCommand("InsertCustomer", con);
cmd.CommandType = CommandType.StoredProcedure;
//this check is necessary, when u don't pass any value as it will pass as [default] and will give error
if (string.IsNullOrEmpty(FirstName))
FirstName = string.Empty;
if (string.IsNullOrEmpty(LastName))
LastName = string.Empty;
if (string.IsNullOrEmpty(MiddleName))
MiddleName = string.Empty;
if (string.IsNullOrEmpty(Desgination))
Desgination = string.Empty;
if (string.IsNullOrEmpty(Address))
Address = string.Empty;
if (string.IsNullOrEmpty(City))
City = string.Empty;
if (string.IsNullOrEmpty(State))
State = string.Empty;
if (string.IsNullOrEmpty(Country))
Country = string.Empty;
cmd.Parameters.AddWithValue("#IV_FirstName", FirstName);
cmd.Parameters.AddWithValue("#IV_LastName", LastName);
cmd.Parameters.AddWithValue("#IV_MiddleName", MiddleName);
cmd.Parameters.AddWithValue("#IV_Desgination", Desgination);
cmd.Parameters.AddWithValue("#IV_Address", Address);
cmd.Parameters.AddWithValue("#IV_City", City);
cmd.Parameters.AddWithValue("#IV_State", State);
cmd.Parameters.AddWithValue("#IV_Country", Country);
using (con)
{
con.Open();
cmd.ExecuteNonQuery();
}
}
Button Save for inserting record.
//Insert record Save Button
protected void btnSave_Click(object sender, EventArgs e)
{
Customer.InsertParameters["FirstName"].DefaultValue = GetGridTextBoxValue("txtFirstName");
Customer.InsertParameters["MiddleName"].DefaultValue = GetGridTextBoxValue("txtMiddleName");
Customer.InsertParameters["LastName"].DefaultValue = GetGridTextBoxValue("txtLastName");
Customer.InsertParameters["Desgination"].DefaultValue= GetGridTextBoxValue("txtDesgination");
Customer.InsertParameters["Address"].DefaultValue = GetGridTextBoxValue("txtAddress");
Customer.InsertParameters["City"].DefaultValue = GetGridTextBoxValue("txtCity");
Customer.InsertParameters["State"].DefaultValue = GetGridTextBoxValue("txtState");
Customer.InsertParameters["Country"].DefaultValue = GetGridTextBoxValue("txtCountry");
Customer.Insert();
}
GetGridTextBoxValue function will get TextBox text value from footer row of respective column.
//Get TextBox value of GridView Footer Row
public string GetGridTextBoxValue(string txtID)
{
try
{
TextBox txt = (TextBox)gvCustomer.FooterRow.FindControl(txtID); // here you can place any text box value on your design page
return txt.Text;
}
catch (Exception ex)
{
return string.Empty;
throw ex;
}
}
and the results image is like this ...