Passing Parameters to Dynamic Menu Data Sources

As mentioned in the Working with Dynamic Menu Data Sources topic, methods that are used as dynamic sources must be parameterless, but sometimes these data sources depend on certain values, such as current user ID, network type, etc. This topic describes how you can customize the return values of your Dynamic Menu Data Sources.

The reason Code Effects component doesn't allow parameters in dynamic sources is because it's practically impossible for the host application to pass parameters to a dynamic source method while Code Effects engine is invoking it during rule evaluation, but it is possible to customize the return of the method based on other fields declared in the same class. For example, consider the following class:

public class TestUtility
{
	// Private field that we will use to customize
	// the return of the GetTestNumbers() method
	private int test;
 
	// Public c-tor that takes
	// the value of the test fields 
	public TestUtility(int testValue)
	{
		this.test = testValue;
	}
 
	// Parameterless method that can be
	// used as a Dynamic Menu Data Source
	public List<DataSourceItem> GetTestNumbers()
	{
		List<DataSourceItem> list =
			new List<DataSourceItem>();
 
		// Customize the return of this method
		// based on the value of "test" field
		if (this.test > 4)
		{
			list.Add(new DataSourceItem(5"Five"));
			list.Add(new DataSourceItem(6"Six"));
		}
		else
		{
			list.Add(new DataSourceItem(1"One"));
			list.Add(new DataSourceItem(2"Two"));
		}
 
		return list;
	}
}

It's easy to see that this class declares the private test field and parameterless public method GetTestNumbers() that returns a collection of DataSourceItem types. The return of the method is based on the value of the test field. We are going to use this method as a dynamic source a bit later in this topic.

In order to be able to use a method with a customizable return as a dynamic data source without hard-coding its name into the static DataAttribute, both the Asp.RuleEditor and the MVC.RuleEditor classes must set the value of the property called DataSources, which our code example is going to use. Let's continue with our code example by declaring a simple source object:

public class TestSource
{
	[Field(DataSourceName = "Numbers")]
	public int TestNumber { getset; }
 
	// The rest of the class goes here...
}

Notice that in this case we don't decorate the entire source class with the DataAttribute in order to specify our GetTestNumbers() method as a dynamic source. Only the FieldAttribute is used on the TestNumber property to specify that the "Numbers" data source should be used as its input.

Now that we have the utility class that declares our dynamic source and the source object that has a property that uses that dynamic source as its value input, we need to bring it all together by telling Code Effects that our GetTestNumbers() method is the data source called "Numbers". We can do this by creating a collection named GetDataSourceDelegate delegates and giving it to the RuleEditor class:

[HttpGet]
public ActionResult Index()
{
	// Create an instance of the TestUtility class
	// and pass it your variable, in this example a value of 2
	TestUtility ts = new TestUtility(2);
 
	// Create a holder for the named delegate
	DataSourceHolder holder = new DataSourceHolder();
 
	// Create a delegate that references your dynamic source
	holder.Delegate = new GetDataSourceDelegate(ts.GetTestNumbers);
 
	// Name that delegate, so Web Rule and your
	// rule fields can refer to it later
	holder.Name = "Numbers";
 
	// Create a list to contain the delegate
	List<DataSourceHolder> dataSources =
		new List<DataSourceHolder>();
 
	// Add the delegate to the list
	dataSources.Add(holder);
 
	// Add the list to the ViewBag
	ViewBag.Numbers = dataSources;
 
	return View();
}

Obviously, the value of "2" that was passed to the TestUtility class can be any value your dynamic source method depends on. The view should pass the collection of delegates to the RuleEditor:

<div>
	@{
		Html.CodeEffects().RuleEditor()
			.Id("Filter")
			.Mode(RuleType.Filter)
			.Rule(ViewBag.Rule)
			.DataSources(ViewBag.Numbers)
			.Render();
	}
</div>

(The assignment of ViewBag.Rule was omitted from the controller's code for clarity.)

This code looks a little convoluted, so let's go through the whole thing one more time:

  • The goal was to be able to customize the return of a dynamic source method.
  • To do that, we declared a class called TestUtility that contains a public parameterless method that can be used as a dynamic source for the property TestNumber of our source object called TestSource.
  • Inside of an MVC action, we declared a list of DataSourceHolder classes and added to it a single holder that contains a named delegate that references our method. The view passes that list to Code Effects, allowing it to call the instance method when the dynamic menu source is needed on the client.
  • Because this scenario allows reference(s) to the dynamic source method(s) to be created, named, and passed to Code Effects dynamically at the last moment, there is no need to decorate the source object with the static DataAttribute(s) in order to name the dynamic source method(s).

If we were to run our imaginary MVC app, we would see the following UI:

Post your support requests on Stackoverflow.com. You can also post your comments and product feedback using the form at the bottom of this page.
Comments: 0
Name (optional):
Comment (URLs are allowed and must start with http:// or https://; all tags will be encoded):
Remaining character count: