This is a SmartObject Service which supports web services. User specifies the web service URL and the service builds itself dynamically. It is similar to the Dynamic SmartObject Service Seb wrote, except for web services instead of databases. The service supports web methods which return void, value type/string and value type/string arrays, as well as custom objects and custom object arrays. Unsupported return types: object, object[], ArrayList (or really any kind of ICollection), DataTables, Da
Hi Colin,
Great work! I see that the Input Parameters are currently restricted to value types and string objects. Could this be extended to accommodate complex types by applying the logic used to map return fields? If so, how would a complex type that contained a List<T> or an array of another complex type fare? For example, an Order object containing a List<OrderItem> property.
Regards
Simon Cragg
Hmm. It might be possible, but that poses some significant challenges which is why I chose not to do it. The basic problem is that with a webservice, you don't know (and shouldn't need to) how a webmethod is implemented.
Currently, the service object just looks at the webmethod signature to generate the proxy using the WSDL, but trying to support custom objects as parameters really would require a greater understanding of the actual code within the webmethod which we don't have access to from the WSDL.
For example, let's say I have a class called Order which has 20 different public properties/fields of value types and some additional number of custom objects also. And let's say I have a method like:
[WebMethod]
Since I only look at the signature and don't know how Order is actually used, I'd have to translate this to a SmartObject service that looked something like:
public OrderDetail GetOrderDetails( Order order )
{
OrderRepository.GetOrderDetails( order.Id );
}
GetOrderDetails( int id, DateTime orderDate, ... )
Except replace the ... with all 20 of the public properties of the class which would be really clunky as you can see that all we really need is id. But it would work, you'd just have a lot of parameters you would have to pass in empty values for.
But now assume that the implementation isn't what I have above, but is instead:
[WebMethod]
public OrderDetail GetOrderDetails( Order order )
{
OrderRepository.GetOrderDetails( order.User, order.orderDate );
}
Here, the method is using a User object (another custom object let's say) and the orderDate to return all order details (this example is just to highlight the challenges and doesn't necessarily make sense). Now assuming we use the same logic we are using for return values then we'd ignore User since we only go one level deep on objects and only support value types so we'd end up not letting you pass in User in our SmartObject call which would mean order.User would be null, which would mean the webmethod doesn't return the value you would expect.
We could instead say, well let's just traverse the entire object graph to create our parameter list. But then we'd get a smartobject method that looked something like:
GetOrderDetails( int id, DateTime orderDate, ..., userId, firstName, lastName, ... )
And our smartobject method would quickly grow to have a huge number of parameters.
When I wrote the SmartObject service, my first thought on a way around this would be to have some kind of schema file in addition to the WSDL for the WebService which would specify what parameters are expected in a situation like that, but that seems like it would be a significant amount of work to implement and requires a deep understanding of the actual webmethod implementation. And it seems to me that if you have that deep of an understanding then you probably have access to the code, so a better alternative would seem to be to just create another webmethod which accepts only the value types required to implement the request. So you'd then have code like:
[WebMethod]
public OrderDetail GetOrderDetails( Order order )
{
OrderRepository.GetOrderDetails( order.User, order.orderDate );
}
[WebMethod]
public OrderDetail GetOrderDetailsForUserName( string userName, DateTime orderDate )
{
User user = new User();
user.UserName = userName;
GetOrderDetails( user, orderDate );
}
If you have any thoughts on ways to overcome the challenges posed, I am certainly open to suggestions.
I went through all the install instructions, but I am receiving this error when trying to put in a web service URL. Any ideas?
Thanks
I think you forgot to add the error message?
Yeah, if you could provide the error I might have a better chance of being able to help. There is a new version which was just released, so perhaps try downloading that version and see if it works any better for you.
Got the Broker installed and set up the smartobject to go with it.
When the workflow runs I get the following error in the process instance - taken from the Host Server Log:
"1401486","2008-08-14 12:53:34","Debug","General","15","GeneralDebugMessage","ProcessInstance.HandleException","15 DestinationRule: Message: Exception has been thrown by the target of an invocation.; ServiceName: DirectivesSupport; ServiceGuid: 3a6e06ed-4105-4e66-b27c-71bbe0caa4a3; InnerExceptionMessage: ;
at SourceCode.Workflow.Runtime.Extenders.WinWFExtender.OnExecute(Object context, XmlElement data, ResolverManager resolverManager)
at SourceCode.Workflow.Runtime.Extenders.ResolverExtenderBase.Execute(Object context, String data)
at K2AppDomainManager.ExecuteExtender(String name, String data, Object ctxt)
at K2AppDomainManager.ExecuteExtender(String name, String data, Object ctxt)
at SourceCode.KO.ProcessInstance.ExecuteExtender(Guid code, State state, ContextType ctxt, Object ctxtobj, Int32 objid, String ctxtname, Guid ecode)","","","i3Workflow:c:program filesk2 blackpearlHost ServerBin","1401486","63a6be964a254b468592598d3c7a0645",""
Am I missing something somewhere?
I haven't seen that behavior before. Have you tried debugging the service? You just need to attach to the K2HostServer.exe process running on the server.
Maybe that will provide more information.
Unfortunatetly, there is no development environment on that machine.
You can debug the process remotely. Just attach to the K2HostServer.exe process on the server from your development machine.
If that isn't possible for whatever reason, you might have to resort to writing log information out somewhere to try to find more info. Or you could try a much simpler web service and see if that works, perhaps it is an issue with one of your web service methods/inputs/return types. If a very simple service doesn't work, then it's probably a configuration/permission error.
I have registered the service broker in both a development and test environment. In both environemnts when I go to add the service I enter the url of the web service and when I press next I get a valiation error dialog box that says:
"Could not load file or assembly 'file:///C:Documents and Settingsk2svcLocal SettingsTempl7uxpdap.dll' or one of its dependencies. The system cannot find the file specified."
The actual file name changes each time I try this process. Can you tell me what might be causing this problem?
danalstr:I have registered the service broker in both a development and test environment. In both environemnts when I go to add the service I enter the url of the web service and when I press next I get a valiation error dialog box that says:
"Could not load file or assembly 'file:///C:Documents and Settingsk2svcLocal SettingsTempl7uxpdap.dll' or one of its dependencies. The system cannot find the file specified."
The actual file name changes each time I try this process. Can you tell me what might be causing this problem?
The service object generates a web service proxy object using the .NET CodeDom assemblies so that it can use reflection to access information about the webservice (methods, parameters, return types, etc.). That is the randomly named .dll you are using.
So, this sounds like some sort of permissions error with your service account accessing the temporary files folder. You could try adding this line at line 148 of WebserviceAccessor.cs
parms.GenerateInMemory =
true;So then it looks like this:
// Compile the assembly with the appropriate references
string[] assemblyReferences = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };
CompilerParameters parms = new CompilerParameters(assemblyReferences);
parms.GenerateInMemory = true;
CompilerResults results = provider1.CompileAssemblyFromDom(parms, compileUnit);
I think that would fix your issue because it would no longer be writing to disk.
I made this change and recieved the same error. I restarted the K2 Service and still the same result.
I will work with it some more on Monday as I will be out for the next few days.
Thanks for your quick response!!!!
I have done some troublshooting and found that I am getting the error on this line:
_webServiceAssembly = results.CompiledAssembly;
Even with the "parms.GenerateInMemory = true;" I still get the error. Do I need to specify the TempFiles location? I have made sure that the user that the K2 server is running under has access to the file path that is claiming to have the error.
Let me know what else I can try.
Hi,
I'm running into problems using this service for custom objects. I did a simple hello world return as a string and the service worked fine, but returning a custom object fails with this error. I've tried a couple different custom objects and all fail this way. The web service tests fine, but no luck through K2 and this service. Any ideas?
If you have a copy of the sourcecode, I would attach a debugger to the K2HostServer.exe and set a breakpoint to see what is happening inside.
Hi danalstr,
Did you figure this one out? We're seeing this issue now too.
Thanks,
JDK
Oh, actually, that post from Colin seemed to resolve it. There was no confirmation so I assumed it didn't work at first.
JDK
Hi All,
I download the dynamic webservice and added into K2 workspace, created the service instance with webservice Url, but when i try the access through context browser i am not getting any webmethods in that.
Please help me out!
Hello, I have the same kind of problem...
It seems that the Dynamic Web Service is not capable of reading certain return type.
For my project, my customer returns a structure made of three value type, and the Dynamic Web Service can't read it...
Dont know why...
If someone has a clue...
I don't know that particular answer, but I do know the most current version (4) has a serious bug. I hope to upload a fix for that specific problem in a few days.
A new versiobn of the Dynamic Web Service (beta 5) has been uploaded. This should fix the bug where you started getting "Object Not Set..." errors when you added more than one instance of the service. There are no new features or enhancements.
Any body confirm, does this support Arraylist or Dataset return date type from webservice's webmothod?
He said it does not support it one of the other threds and given a work around
http://k2underground.com/forums/thread/29972.aspx
It does support arrays so you could convert your arraylist to an array and return that.
The project comes with source code so you can see exactly what it supports and enhance it with additional features.
Hi Guys,
I've made some changes to the version available here. The changed version can be found on github:
https://github.com/cyclops1982/DynamicWebService
Reply
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.