My dilemma is, basically, how to share an enumeration between two applications.
The users upload documents through a front-end application that is on the web. This application calls a web service of the back-end application and passes the document to it. The back-end app saves the document and inserts a row in the Document table.
The document type (7 possible document types: Invoice, Contract etc.) is passed as a parameter to the web service's UploadDocument method. The question is, what should the type (and possible values) of this parameter be?
Since you need to hardcode these values in both applications, I think it is O.K. to use a descriptive string (Invoice, Contract, WorkOrder, SignedWorkOrder).
Is it maybe a better approach to create a DocumentTypes enumeration in the first application, and to reproduce it also in the second application, and then pass the corresponding integer value to the web service between them?
I'd suggest against passing an integer between them, simply for purposes of readability and debugging. Say you're going through your logs and you see a bunch of 500 errors for DocumentType=4. Now you've got to go look up which DocumentType is 4. Or if one of the applications refers to a number that doesn't exist in the other, perhaps due to mismatched versions.
It's a bit more code, and it rubs the static typing part of the brain a bit raw, but in protocols on top of HTTP the received wisdom is to side with legible strings over opaque enumerations.
I would still use enumeration internally but would expect consumers to pass me only the name, not the numeric value itself.
just some silly example to illustrate:
public enum DocumentType
{
Invoice,
Contract,
WorkOrder,
SignedWorkOrder
}
[WebMethod]
public void UploadDocument(string type, byte[] data)
{
DocumentType docType = (DocumentType)Enum.Parse(typeof(DocumentType), type);
}
I can only speak about .net, but if you have an ASP.net Webservice, you should be able to add an enumeration directly to it.
When you then use the "Add Web Reference" in your Client Application, the resulting Class should include that enum
But this is from the top of my head, i'm pretty sure i've done it in the past, but I can't say for sure.
In .NET, enumeration values are (by default) serialized into xml with the name. For instances where you can have multiple values (flags), then it puts a space between the values. This works because the enumeration doesn't contain spaces, so you can get the value again by splitting the string (ie. "Invoice Contract SignedWorkOrder", using lubos's example).
You can control the serialization of values of in asp.net web services using the XmlEnumAttribute, or using the EnumMember attribute when using WCF.
If you are consuming your Web service from a .NET page/application, you should be able to access the enumeration after you add your Web reference to the project that is consuming the service.
If you are not working with .NET to .NET SOAP, you can still define an enumerator provided both endpoints are using WSDL.
<s:simpleType name="MyEnum">
<s:restriction base="s:string">
<s:enumeration value="Wow"/>
<s:enumeration value="This"/>
<s:enumeration value="Is"/>
<s:enumeration value="Really"/>
<s:enumeration value="Simple"/>
</s:restriction>
</s:simpleType>
Its up to the WSDL -> Proxy generator tool to parse that into a enum equivalent in the client language.
There are some fairly good reasons for not using enums on an interface boundary like that. Consider Dare's post on the subject.
I've noticed that when using "Add Service Reference" as opposed to "Add Web Reference" from VS.net, the actual enum values come across as well as the enum names. This is really annoying as I need to support both 2.0 and 3.5 clients. I end up having to go into the 2.0 generated web service proxy code and manually adding the enum values every time I make a change!
Related
My dilemma is, basically, how to share an enumeration between two applications.
The users upload documents through a front-end application that is on the web. This application calls a web service of the back-end application and passes the document to it. The back-end app saves the document and inserts a row in the Document table.
The document type (7 possible document types: Invoice, Contract etc.) is passed as a parameter to the web service's UploadDocument method. The question is, what should the type (and possible values) of this parameter be?
Since you need to hardcode these values in both applications, I think it is O.K. to use a descriptive string (Invoice, Contract, WorkOrder, SignedWorkOrder).
Is it maybe a better approach to create a DocumentTypes enumeration in the first application, and to reproduce it also in the second application, and then pass the corresponding integer value to the web service between them?
I can only speak about .net, but if you have an ASP.net Webservice, you should be able to add an enumeration directly to it.
When you then use the "Add Web Reference" in your Client Application, the resulting Class should include that enum
But this is from the top of my head, i'm pretty sure i've done it in the past, but I can't say for sure.
If you're using .NET you can create an enumeration on the back end. Then create a web reference on the front end to that back end web service. That will then pick up the enumeration and expose it there on the front end, while only having it defined in one place.
The advantage with using the enumerations is that you can expose those on the front end, avoiding the problem of users passing in bad values. If you were to use an integer, that isn't very friendly and you'd have to check it at some point. Similar problem with strings. So if you have a well known set of values, I'd highly recommend using an enumeration.
I consume a web service that has a numeric element. The Delphi wsdl importer sets it up as Int64.
The web service allows this element to be blank. However, because it is defined as Int64, when I consume the web service in Delphi without setting a value for it, it defaults to 0 because it's an Int64. But I need it to be blank and the web service will not accept a value of 0 (0 is defined as invalid and returns an error by the web service).
How can I pass a blank value if the type is Int64?
Empty age (example)
<E06_14></E06_14>
could have a special meaning, for example be "unknown" age.
In this case, the real question is how to make the field nillable on the Delphi side.
From this post of J.M. Babet:
Support for 'nil' has been an ongoing issue. Several built-in types of
Delphi are not nullable. So we opted to use a class for these cases
(not elegant but it works). So with the latest update for Delphi 2007
I have added several TXSxxxx types to help with this. Basically:
TXSBoolean, TXSInteger, TXSLong, etc. TXSString was already there but
it was not registered. Now it is. When importing a WSDL you must
enable the Use 'TXSString for simple nillable types' option to make
the importer switch to TXSxxxx types. On the command line it is the
"-0z+" option.
The DocWiki for the Import WSDL Wizard also shows two options related to nillable elements:
Process nillable and optional elements - Check this option to make the WSDL importer generate relevant information about optional
and nillable properties. This information is used by the SOAP runtime
to allow certain properties be nil.
Use TXSString for simple nillable types - The WSDL standard allows simple types to be nil, in Delphi or NULL, in C++, while Delphi
and C++ do not allow that. Check this option to make the WSDL importer
overcome this limitation by using instances of wrapper classes.
Here is a description of the scenario and I would appreciate also any comments on the approach used
The core of my application is a set of web services backed by a P2P database. One service accepts a simple XML-based record (I have designed a generic schema for it). The service processes this data (mainly creating keys based on certain criteria) and pass the original data along with the created keys to a listening SocketServer in one of the listening P2P nodes. This key,data pair is routed to the proper node, which stores the data (associated with the key as an ID) in an XML database.
A second service accepts a query document that is structured based on the same schema, but with optional values that would be used for searching and matching from the previously stored ones. So the second service would pass this query (with the proper keys) to the P2P part, get back the results and pass them back to the service client.
E.g. if the original record submitted to the first service was < attr1 >value1 < /attr1 > < attr2 > value2 < / attr2 > (attribute list along with some other metadata mandated by the schema) then the second service should retrieve that record if the query received was < attr2 >value2 < / attr2 >
(I could later think about using more complex XPath or XQuery queries as the underlying XML database allows instead of exact matches for values here but that is not important at this stage. there is also a third service I am working on but it depends on getting the first two in proper shape first)
So my questions are:
1) What data type should I use as the parameters of the web services? How to utilize my schema for this usage? I was considering various XML binding frameworks (especially JAXB and SDO) for this but didn't know how to proceed.
2) How can I enhance the two services (call them store and search) to use dynamically created templates based on the original generic schema? The service would still accept documents of the main schema type but has the inner attribute list based on a template say template1 only requires whose values are ints while template2 require (float) and (string). The current JSP-based prototype manually creates this template but as an XML document that is assembled by hand (<>tags dispersed in text) and there is no type checking what so ever so I thought I could do better!
3) Is it possible to generate a quick web app prototype for simple access to this system (again by using the schema (&templates) to edit the appropriate XML message structures? What I am looking for is for the (human) user to choose a template and then just "fill in the blanks" and submit, no need for any fancy look and feel.
4) Can I or how can I also use this XML message type for communicating across sockets?
5) Does it matter if I deploy the services as stateless EJBs or not? Do I need them to be EJBs or servlets would be more than enough?
I currently have a rudimentary implementation (from previous developers) that were meant for a subset of my current requirements (I am improving on the services and adding new derived ones) but there was no schema nor validation and the data is passed all along as basic strings, thus providing weak typing and difficult to update manual parsing. The reason I want to update this to a stronger bound typing is to introduce changes in the data schema that would be passed along the whole system easily. Basically I want the system to be as less coupled to the data format/schema used as possible; the current prototype is too coupled to the data that I am finding it extremely difficult to change the data without breaking the system.
My initial investigation led me to consider JAXB but it supports only static typing (cannot create a schema/types dynamically at runtime that I want to persist for later usage). So I came across SDO which has both dynamic and static typing. The problem is just that there is not enough community and/or examples of using this approach so it seems risky (the examples of Apache Tuscany and Eclipselink implementations are very scarce and I could not find complete examples that are not 5+ years old (like this http://www.ibm.com/developerworks/java/library/j-sdo/) and also tackles the XML use case of SDO (most seem to focus on the relational usage of SDO).
This is my first time asking for programming help (here and elsewhere) so please bear with me. I searched a lot on the net but I could not find anything useful but pieces here and there that did not add up.
Any comment or hint is really appreciated.
trfndr
EDIT
I forgot one thing: how would the search service get back the results? Since it is opening a client socket connection, there is no way to get back any results synchronously. The current implementation tackles this by having the service client opening a listening socket on a random port and putting this contact info in the query document. After the search web service sends the query to the p2p part it finishes. The p2p sends the results as a WS call to another service which sends them back to the service client socket. I don't like this approach much, is there any more elegant solution?
I lead the EclipseLink JAXB & SDO implementations and represent Oracle on those specifications so hopefully I can help you out. This question is very similar to talk I'm giving at JavaOne in September.
1) What data type should I use as the
parameters of the web services? How to
utilize my schema for this usage? I
was considering various XML binding
frameworks (especially JAXB and SDO)
for this but didn't know how to
proceed.
This depend's on what web service framework you are using. JAXB is much easier to use with JAX-WS, and while JAXB is still easier to use with JAX-RS SDO, is a possible alternative.
2) How can I enhance the two services
(call them store and search) to use
dynamically created templates based on
the original generic schema? The
service would still accept documents
of the main schema type but has the
inner attribute list based on a
template say template1 only requires
whose values are ints while template2
require (float) and (string). The
current JSP-based prototype manually
creates this template but as an XML
document that is assembled by hand
(<>tags dispersed in text) and there
is no type checking what so ever so I
thought I could do better!
I'm not 100% what you mean here, but the following may be helpful:
Using #XmlAnyElement to Build a Generic Message
3) Is it possible to generate a quick
web app prototype for simple access to
this system (again by using the schema
(&templates) to edit the appropriate
XML message structures? What I am
looking for is for the (human) user to
choose a template and then just "fill
in the blanks" and submit, no need for
any fancy look and feel.
JAX-RS is a nice framework for creating quick prototypes. Below is an example I created:
Part 1 - The Database
Part 2 - Mapping the Database to Objects
Part 3 - Mapping the Objects to XML
Part 4 - The RESTful Service
Part 5 - The Client
4) Can I or how can I also use this
XML message type for communicating
across sockets?
I prefer frameworks like JAX-RS that communicate over the HTTP protocol.
5) Does it matter if I deploy the
services as stateless EJBs or not? Do
I need them to be EJBs or servlets
would be more than enough?
My preference is to use an EJB session bean for the service. If you are interacting with a database then you can leverage the Java Transaction API (JTA) to manage your database transactions.
Part 4 - The RESTful Service
SDO
EclipseLink is the SDO 2.1.1 (JSR-235) reference implementation. We have some examples posted below. If you are looking how to do something specific, I will try to post a relevant example.
http://wiki.eclipse.org/EclipseLink/Examples/SDO
JAXB
JAXB is static. It is also more popular than SDO. Recognizing this in EclipseLink we have implemented a dynamic JAXB feature. It gives you the dynamic aspect of SDO with a JAXB slant.
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic
EDIT #1
Since you are dealing with JAX-WS and your model is almost entirely dynamic, I think you should skip the JAXB binding altogether. In the following link see the section "Switching Off Data Binding"
http://java.sun.com/developer/technicalArticles/xml/jaxrpcpatterns3/
This will give us the body of the message as a javax.xml.transform.Source object. We will need to process the XML based on the dynamic templates. SDO would be a good choice here. You can constantly add new types to the HelperContext using XML schemas.
helperContext.getXSDHelper().define(schema1, null);
helperContext.getXSDHelper().define(schema2, null);
You wil be able to unmarshal the Source from the web service as follows:
XMLDocument doc = helperContext.getXMLHelper().load(source, null, null);
DataObject rootDataObject = doc.getRootObject();
String someValue = rootDataObject.getString("attr3/childAttr/anotherChildAttr");
You will also be able to use the XMLHelper to marshal your objects to XML when calling another service.
I have an ASP.net web service that I'm using for a web application which returns a either XML or JSON data to me, depending on the function I call. This has been working well thus far, but I've run into a problem. I want to create an "export" link on my page that will download a JSON file. The link is formatted very simply:
Export This Item
As you might imagine, this should export item 2. So far so good, yes?
Problem is that since I'm not specifically requesting that the accepted content type is JSON, ASP.net absolutely refuses to send back anything but XML, which just isn't appropriate for this situation. The code is essentially as follows:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Item ExportItem(int itemId)
{
Context.Response.AddHeader("content-disposition", "attachment; filename=export.json"); //Makes it a download
return GetExportItem(itemId);
}
Despite my specifying the ResponseFormat as JSON, I always get back XML unless I request this method via AJAX (using Google Web Toolkit, BTW):
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, "mywebserviceaddress/ExportFunc");
builder.setHeader("Content-type","application/json; charset=utf-8");
builder.setHeader("Accepts","application/json");
builder.sendRequest("{\"itemId\":2}", new RequestCallback(){...});
That's great, but AJAX won't give me a download dialog. Is there any way to force ASP.net to give me back JSON, regardless of how the data is requested? It would seem to me that not having a manual override for this behavior is a gross design oversight.
QUICK ANSWER:
First off, let me say that I think that womp's answer is probably the better way to go long term (Convert to WCF), but deostroll led me to the answer that I'll be using for the immediate future. Also, it should be noted that this seems to work primarily because I wanted just a download, may not work as well in all situations. In any case, here's the code that I ended up using to get the result I wanted:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ExportItem(int itemId)
{
Item item = GetExportItem(itemId);
JavaScriptSerializer js = new JavaScriptSerializer();
string str = js.Serialize(item);
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.AddHeader("content-disposition", "attachment; filename=export.json");
Context.Response.AddHeader("content-length", str.Length.ToString());
Context.Response.Flush();
Context.Response.Write(str);
}
Please note the return type of void (which means that your WDSL will be next to useless for this function). Returning anything will screw up the response that is being hand-built.
Asp.net web services are SOAP-based web services. They'll always return XML. The Ajax libraries came along and the ScriptMethod stuff was introduced, but it doesn't change the underlying concept of it.
There's a couple things you can do.
WebMethods are borderline obsolete with the introduction of WCF. You might consider migrating your web services to WCF, in which you'll have much greater control over the output format.
If you don't want to do that, you can manually serialize the result of your webservice calls into JSON, and the service will wrap that in a SOAP header. You would then need to strip out the SOAP stuff.
Here are two forums threads for your reference:
http://forums.asp.net/t/1118828.aspx
http://forums.asp.net/p/1054378/2338982.aspx#2338982
I have no clear idea. They say on concentrating on setting the content type to application/json. I haven't worked with wcf before, but I think you can make use of the Response object.
Set the content type on the response object. Do a response.write passing your json data as string and then do a response.end.
Just thought I'd throw this out there since it wasn't mentioned previously... if you use WebServices with ASP.NET 3.5, JSON is the default return format. It also comes along with JSON serializer so you can stop using the JavascriptSerializer.
This article on Rick Strahl's blog talks about the strongly-typed conversion you can do between server side classes and JSON objects from the client.
I've recently completed a project using this new JSON stuff in .NET 3.5, and I'm extremely impressed with the performance. Maybe it's worth a look...
When coding web services, how do you structure your return values? How do you handle error conditions (expected ones and unexpected ones)? If you are returning something simple like an int, do you just return it, or embed it in a more complex object? Do all of the web methods within one service return an instance of a single class, or do you create a custom return value class for each method?
I like the Request/Response object pattern, where you encapsulate your arguments into a single [Operation]Request class, which has simple public properties on it.
Something like AddCustomerRequest, which would return AddCustomerResponse.
The response can include information on the success/failure of the operation, any messages that might be used by the UI, possibly the ID of the customer that was added, for example.
Another good pattern is to make these all derive from a simple IMessage interface, where your general end-point is something like Process(params IMessage[] messages)... this way you can pass in multiple operations in the same web request.
+1 for Ben's answer.
In addition, I suggest considering that the generic response allow for multiple error/warning items, to allow the reply to be as comprehensive and actionable as possible. (Would you want to use a compiler that stopped after the first error message, or one that told you as much as possible?)
If you're using SOAP web services then SOAP faults are the standard way to return error details, where the fault messages can return whatever additional detail you like.
Soap faults are a standard practice where the calling application is a Soap client. There are cases, such as a COM client using XMLHTTP, where the Soap is parsed as XML and Soap faults cannot be easily handled. Can't vote yet but another +1 for #Ben Scheirman.