Why is not OK to pass in a Collection<int> parameter in a Web method?  
Author Message
Namza





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Hello there.

I have a web service that contains the following web method:

using System.Collections.ObjectModel;

...

[WebMethod]

public void GetUsers(Collection<int> userIds)

{

// Do something here

}

Now, I have a Windows client that web references the above web service and consumes the web method:

using System.Collections.ObjectModel;

...

private void GetUsersData()

{

Collection<int> myUserIds = new Collection<int>();

myUserIds.Add(1);

myUserIds.Add(2);

myUserIds.Add(3);

myUserIds.Add(4);

myUserIds.Add(5);

localhost.Service myService = localhost.Service();

myService.GetUser(myUserIds); // Problem here!!!

}

The problem is, VS.NET expects me to pass in a parameter of type int[] when I call the GetUser web method, eventhough the web method's pass-in parameter is of type Collection<int>.

How do I make it possible for the client to pass in a Collection<int> parameter Or is it just not possible to do so

Thank you.



Visual C#11  
 
 
frederikm





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Hi

the thing is you are using visual studio.net (ie .net 1.1) as a consumer of a webservice in .net 2.0.
generics are new in 2.0 so .net 1.1 does not support tem, instead you use an array of int.

Hope this helps



 
 
Namza





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Hi frederikm. Thanks for the quick reply. Actually I am using VS2005 (.NET FW 2.0) to write both the web service and the consumer. Any thoughts

Thanks.


 
 
timvw





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Have a look at the (generated) WSDL... You will see that the signature talks about an array instead of a generic list...


 
 
frederikm





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

hi

Blimey!

according to http://www.devx.com/dotnet/Article/30158/0/page/4 it seems this is the normal behaviour...

this is not really a hard issues seeing as you can:

int[] array = service.getInts();

List<int> list = new List<int>(array);

and

list.ToArray();

Hope this helps

 

 



 
 
Eric Oostergo





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Dear Namza,

The answer is quite simple... wsdl and xsd doesn't support generics as this is a platform feature. One thing you could try is to download Thinktecture's Web Service Contract First which will allow you to generate a client-side proxy that does use generics.

Another solution is to manually change the generated client-side proxy from the array into a generic list as .NET will know how to serialize this back to an array.

Hope this helps.

Regards,

Eric.


 
 
Namza





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Guys, thank you for all your suggestions and for shedding light to this issue. I will explore each of your suggestion. In the mean time, in the interest of time, I think I will just resort to array of int.

By the way, Eric, could you kindly give me a code example on how to manually change the generated client-side proxy from array into generic list

Thanks again, guys. You have been a great help.


 
 
Eric Oostergo





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Dear Namza,

If you use "Add Web Reference" in a project, Visual Studio 2005 will generate the following (proxy-)code of the method you specified:

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/GetUsers", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public void GetUsers(int[] userIds)
{
this.Invoke("GetUsers", new object[] {userIds});
}

You can reach this code by clicking Show All Files in the solution explorer and by expanding your web reference node untill you can open Reference.cs.
The only thing you have to do now is to add a using directive to System.Collections.ObjectModel and change the int[] to Collection<int>.
Now you can code directly using the Collection<int> datatype without having to use arrays.

An obvious drawback is that if you change your webservice, you will have to regenerate the proxy and you will then loose this modification. A better solution would be to use Web Services Contract First (as described earlier) or to use Windows Communication Foundation where you can reuse your data contract. Whatever you decide to do, I strongly advise you to implement a service agent pattern. This will allow you to call the service agent from your client code and the service agent will handle the actual call to the webservice using the proxy object. The service agent will then contain code to convert the collection to an array.

Another thing I would like to suggest is to use a generic List. This type contains a ToArray() method that will directly return an array. Your service agent could use this method to convert the List to array and then pass it to the webservice using the generated proxy.

I hope this helps. If you have any more questions, let me know (and i'll try to answer more quickly )

Eric.


 
 
Namza





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Thanks, Eric, for the example and explanation. Will definitely give it a try and ask you more questions if I ever get stuck.

Best regards,

Namza.


 
 
pkarun





PostPosted: Visual C# Language, Why is not OK to pass in a Collection<int> parameter in a Web method? Top

Hi Eric,

I have the following doubt

I have the project being developed in VS 2005 with C# language.

Initially it is designed to have all its components UI,BL,DL all in same client system.Through Data Layer it does Add,Edit,Display and Delete operations.

Database is present is a dedicated server.

With the above approach we have coded some of the modules.

Component Flow - UI talks to Controller --Controller talks to Service class(by using Business entity objects)--Service class talks to Data layer to do DML operations.

Code flow with existing architecture as below

UI

private void buttonDelete_Click(object sender, EventArgs e)

{

try

{

DialogResult dialogResult = this.ShowConfirmationMessageBox(LocaleReader.GetInstance().FindValue(LocaleConstant.DeleteFileKey, false));

if (dialogResult == DialogResult.Yes)

{

this.controller.State.Labors = this.DataGridViewMasterBase.GetSelectedObjects<Controller.localhost.Labor>();

controller.DeleteLabor();

this.FillControls();

}

}

catch (ApplicationException exception)

{

ExceptionPolicy.HandleException(exception, ApplicationConstant.UIExceptionPolicyKey);

this.ShowMessageBox(exception);

}

}

Controller

public void DeleteLabor()

{

try

{

IMasterService masterService = (IMasterService)ServicesFactory.GetInstance().GetService(ServiceConfigurationConstant.MasterServiceKey);

masterService.DeleteLaborCode((IList<Labor>)this.State.Labors);

try

{

service.DeleteLaborCode(this.State.Labors);

}

catch(System.Exception ex)

{

string strexc = ex.Message;

}

}

catch (ApplicationException exception)

{

ExceptionPolicy.HandleException(exception, ApplicationConstant.ControllerExceptionPolicyKey);

throw;

}

}

BL

public void DeleteLaborCode(List<Labor> labors)

{

if (labors == null) throw (new ArgumentNullException());

try

{

//Deletes the specified labors.

ILaborDAO laborDAO = (ILaborDAO)DAOFactory.GetInstance().GetDAO(DAOConfigurationConstant.LaborDAOKey);

DAOFactory.GetInstance().GetTransactionHandler().BeginTransaction();

foreach (Labor labor in labors)

{

if (!laborDAO.IsLaborReferred(labor)) laborDAO.DeleteLaborCode(labor);

else

{

DAOFactory.GetInstance().GetTransactionHandler().RollbackTransaction();

throw (new IsReferencedException(ErrorIdConstant.IsLaborReferencedDeleteMessage));

}

}

DAOFactory.GetInstance().GetTransactionHandler().CommitTransaction();

}

catch (ApplicationException exception)

{

DAOFactory.GetInstance().GetTransactionHandler().RollbackTransaction();

ExceptionPolicy.HandleException(exception, ApplicationConstant.ServiceExceptionPolicyKey);

throw;

}

}

DL

public void DeleteLaborCode(Labor labor)

{

if (labor == null) throw (new ArgumentNullException());

R2D2DbHelper.Write(new DeleteLaborProvider(), labor);

}

Now there is an urgent need to implement Web Services by exposing the service class methods.

Kindly tell me how to implement Web Services with minimal code change.

Since we have used generic List collection across tiers,i faced some problem in consuming web services.Then i altered the generated client proxy method signature to generic list.Then everything worked fine.

Now my question is with minimal code change how to implement Web services

What i did now is i have made all the methods in service class to Web methods and consuming it from the client.

Now in the client side only UI and controller class will be present[Client code wont have its own business entity classes,it will refer the business entity from Web services class]

In the Web Services server we have Service,Business entity and Data Layer classes.

Is the above approach correct

Do we need to introduce any new layer apart from this

Please help me on this ASAP.

Thanks in advance.