Sunday, March 11, 2012

CascadingDropDown and Database

I just wrote a sample for this yesterday. It's easy to do - here's the best way I've found:

1) Add a dataset to your project for each of your tables (say Brand, Model, Color are your tables). In each dataset, and in the dataset designer, create an accessor method that takes the ID of the parent item(s), something like

ModelTable ModelTableAdapter.GetModelsForBrand(int brandID);

ColorTable ColorTableAdapter.GetColorsForModel(int modelID);

BrandTable BrandTableAdapter.GetBrands(); // returns them all

2) Create a webservice with methods to get results for each of these:

[WebMethod]

publicCascadingDropDownNameValue[] GetColorsForModel(

string knownCategoryValues,string category) {

StringDictionary kv =CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

int modelId;

if (!kv.ContainsKey("Model") || !Int32.TryParse(kv["Model"],out modelId))

{

thrownewArgumentException("Couldn't find model.");

}

DBTableAdapters.ColorTableAdapter adapter =new

DBTableAdapters.ColorTableAdapter();

ColorDataTable colorTable = adapter.GetColorsForModel(modelId);

List<CascadingDropDownNameValue> values =new

List<CascadingDropDownNameValue>();

foreach (DataRow drin colorTable) {

values.Add(

newCascadingDropDownNameValue(

(string)dr["Color"],

dr["ColorID"].ToString()));

}

return values.ToArray();

}

This will return you all the colors for a given model. Now you just need to hook up your CascadingDropDown and specify this webservice. Say it's called ModelInfo.asmx:

Brand:<asp:DropDownListID="ddlMake"runat="server"/><br/>

Model:<asp:DropDownListID="ddlModel"runat="server"/><br/>

Color:<asp:DropDownListID="ddlColor"runat="server"/>

<atlasToolkit:CascadingDropDownID="CascadingDropDown1"runat="server">

<atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlMake"

Category="Make"

PromptText="Select a brand"

ServicePath="ModelInfo.asmx"

ServiceMethod="GetBrands"/>

<atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlModel"

ParentControlID="ddlMake"

PromptText="Please select a model"

ServiceMethod="GetModelsForBrand"

ServicePath="ModelInfoService.asmx"

Category="Model"/>

<atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlColor"

ParentControlID="ddlModel"

PromptText="Please select a color"

ServiceMethod="GetColorsForModel"

ServicePath="ModelInfo.asmx"

Category="Color"/>

</atlasToolkit:CascadingDropDown>


Oh - and in "real life" you'll want to do some caching here. This method will result in quite a few calls to the DB.

Do you have tried or have any idea how to force web browser to cache these calls to web services. Behaviour that I see is that they are called with POST requests and they are not cached. How to force them to use GET - Ive seen there are some options, Ive setup the web service to run with GET but how to force client part to make these?


Hi BAlexandrov,

I think Shawn was specifically referring to caching on the server (either simply viaWebMethod'sCacheDuration or possibly via theHttpContext.Current.Cache property). You're right that using GET will cause the local browser to cache the request, but I don't know how well Atlas supports this yet. You may consider asking about it in the Atlas Discussion and Suggestions forum.

Thanks,
Ted

Hello sburke_msft

I see how you have done this for the last DDL item, but I am still having a tough time of this. Can you post your whole page/webservice so that I can get a look at the big picture?

This would help me immensly.

Thanks in advance!

Matt


Here you go...
public class CarData : System.Web.Services.WebService {public CarData () {//Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod]public CascadingDropDownNameValue[] GetMakes(string knownCategoryValues,string category) { CarsTableAdapters.MakeTableAdapter makeAdapter =new CarsTableAdapters.MakeTableAdapter(); Cars.MakeDataTable makes = makeAdapter.GetMakes(); List values =new List();foreach (DataRow drin makes) {string make = (string)dr["Make"];int makeId = (int)dr["MakeID"]; values.Add(new CascadingDropDownNameValue(make, makeId.ToString())); }return values.ToArray(); } [WebMethod]public CascadingDropDownNameValue[] GetModelsForMake(string knownCategoryValues,string category) { StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);int makeId;if (!kv.ContainsKey("Make") || !Int32.TryParse(kv["Make"],out makeId)) {return null; } CarsTableAdapters.ModelTableAdapter makeAdapter =new CarsTableAdapters.ModelTableAdapter(); Cars.ModelDataTable models = makeAdapter.GetModelsForMake(makeId); List values =new List();foreach (DataRow drin models) { values.Add(new CascadingDropDownNameValue((string)dr["Model"], dr["ModelID"].ToString())); }return values.ToArray(); } [WebMethod]public CascadingDropDownNameValue[] GetColorsForModel(string knownCategoryValues,string category) { StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);int modelId;if (!kv.ContainsKey("Model") || !Int32.TryParse(kv["Model"],out modelId)) {return null; } CarsTableAdapters.ColorTableAdapter adapter =new CarsTableAdapters.ColorTableAdapter(); Cars.ColorDataTable colorTable = adapter.GetColorsForModel(modelId); List values =new List();foreach (DataRow drin colorTable) { values.Add(new CascadingDropDownNameValue((string)dr["Color"], dr["ColorID"].ToString())); }return values.ToArray(); } }

Thanks. Unfortunately, I have no idea why this isn't working for me. The HTML looks good and my webservice code looks good. (sigh..)

I get the sample apps to work, so I know it's not a framwork issue. (this works for the CarService XML sample)

In the line:

if (!kv.ContainsKey("Make") || !Int32.TryParse(kv["Make"],out makeId))
{
return null;
}

You are referring to the "Make" as the Category of the ParentControl right? I have this as my HTML:

<myAtlas:CascadingDropDownID="AtlasMonoTypeDDLs"runat="server"><myAtlas:CascadingDropDownPropertiesCategory="Name"TargetControlID="ddlLinkMonoType"PromptText="Please select a Monograph Type."ServiceMethod="GetMonographTypes"ServicePath="MonographListService.asmx"/><myAtlas:CascadingDropDownPropertiesCategory="Monos"TargetControlID="ddlLinkMono"ParentControlID="ddlLinkMonoType"PromptText="Please select a Monograph."ServiceMethod="GetMonographsByTypeID"ServicePath="MonographListService.asmx"/></myAtlas:CascadingDropDown>

The parent dropdown list is populating from the webservice, yet the child list is not, and it's not getting the "greyed out" look that the samples had. I wonder why this isn't working?

Here is my webservice code (note that I am using the Codesmith Nettiers TList object for my datasource, which is like a generic List object that holds my populated business objects).

<WebMethod()>

PublicFunction GetMonographTypes(ByVal knownTypeValuesAsString,ByVal categoryAsString) As CascadingDropDownNameValue()

Dim mTypesListAs TList(Of MonographType) = DataRepository.MonographTypeProvider.GetAll
Dim valuesAsNew List(Of CascadingDropDownNameValue)

ForEach mTypeAs MonographTypeIn mTypesList
values.Add(New CascadingDropDownNameValue(mType.Name, mType.TypeID.ToString))
Next

Return values.ToArray()

EndFunction

<WebMethod()>

PublicFunction GetMonographsByTypeID(ByVal knownTypeValuesAsString,ByVal categoryAsString) As CascadingDropDownNameValue()

Dim kvAs StringDictionary = CascadingDropDown.ParseKnownCategoryValuesString(knownTypeValues)
Dim typeIDAs Int32
If (Not kv.ContainsValue("Name"))Or (Not Int32.TryParse(kv("Name"), typeID))ThenReturnNothing

Dim keyAsString ="MonographName" & typeID
Dim monoListAs TList(Of MonographMain) = DataRepository.MonographMainProvider.GetByTypeID(typeID)
Dim valuesAsNew List(Of CascadingDropDownNameValue)
ForEach monoAs MonographMainIn monoList
values.Add(New CascadingDropDownNameValue(mono.Name, mono.MgID))
Next

Return values.ToArray()

EndFunction


The signature for the web service functions has to matchexactly,including parameter names:

PublicFunction GetMonographsByTypeID(ByValknownTypeValuesAsString,ByVal categoryAsString) As CascadingDropDownNameValue()

Should be

PublicFunction GetMonographsByTypeID(ByValknownCategoryValuesAsString,ByVal categoryAsString) As CascadingDropDownNameValue()


It works! (finally... I feel pretty stupid.)

Thanks for your time. It's been very helpful.


Hi;

Where do you define CarsTableAdapters ?


It's auto-generated from the XSD file.

Hello i am having serious problems with my CDD, i have 5 days and all i get is Error Code 500. i make my web service and i conencted to the objects and still dont work. Please help me.

No comments:

Post a Comment