Interfaces

Project

Pages Html

NuGet packageOwin.Framework.Pages.Html
GitHub sourceOwinFramework.Pages.Html

Home |  Readme

Data provider reference | The OWIN FRamework

Data Provider Elements

Data Provider elements add data to the rendering context so that other elements on the page can use this data.

Data Provider Class Example

All data providers must have a C# implementation to be useful. It is not possible to retrieve data from somewhere and add it to the rendering context by decorating classes with attributes only.

Below is a very simple data provider that illsutrates the basic principal.

    internal class ApplicationInfo
    {
        public string Name => "My Application";
    }
    [IsDataProvider("application", typeof(ApplicationInfo))]
    internal class ApplicationInfoDataProvider : DataProvider
    {
        private readonly ApplicationInfo _applicationInfo;
        public ApplicationInfoDataProvider(IDataProviderDependenciesFactory dependencies)
            : base(dependencies)
        {
            _applicationInfo = new ApplicationInfo();
        }
        protected override void Supply(
            IRenderContext renderContext,
            IDataContext dataContext,
            IDataDependency dependency)
        {
            dataContext.Set(_applicationInfo);
        }
    }

You can see from this example:

  • A Data Provider is a class that inherits from DataProvider or implements the IDataProvider interface.
  • The Data Provider class should be decorated with the IsDataProvider attribute unless you plan to manually register the Data Provider with the Name Manager, or you are including the Data Provider in a package.
  • The IsDataProvider attribute defines the name of the Data Provider, the type of data that it provides, and the context in which it can provide that data.
  • If the Data Provider inherits from the DataProvider class, then it must override the Supply() method and call the Set() method of the Data Context.
It is very important that the Data Provider actually provides the data that it claims to provide through its IsDataProvider attribute. It is OK for the Data Provider to set a null value in the Data Context, but it must not return from the Supply() method without setting any value, because this will result in an infinite loop in the code.

Some other things about Data Providers:

  • A Data Provider can supply multiple kinds of data. In this case you can advertise those other data types by adding SuppliesData attributes to the Data Provider class.
  • When page elements need data they can specify a data context name. This can be used to differentiate between multiple providers of the same kind of data, or these contexts can all be handled by the same data provider.

    The IsDataProvider attribute and the SuppliesData attribute have an optional data context name that makes the Data Provider specific to that context for that type of data. If the optional data context name is not set then the Data Provider is advertising that it can fulfil this type of data for any context, in which case it needs to examine the IDataDependency parameter passed to the Supply() method, and supply data in the requested context.

    As an example of using different data context names, consider a website where you can view the profile pages of other users. On this page you want to data bind to a user view model, but there are two possible users, the user whose profile page you are viewing or the user who is logged into the website. In this situation you can create separate Data Providers for these use cases, or have one Data Provider that handles both.

    A Data Provider can have a dependency on another named data provider, or a specific type of data. For example I might have a Data Provider for customer data and a Data Provider for a list of customer orders that depends on the customer Data Provider. You can define these dependencies by decorating your Data Provider class with the NeedsData attribute.

Below is an example of a Data Provider that depend on other data. This is a more complex example where PersonListProvider supplies a list of people and PersonAddressProvider does not directly depend on the data provided by PersonListProvider, but depends on a single person. These Data Providers assume that there will be a repeating Region on the page that enumerates the people and places each person in context to fulfill the needs of the PersonAddressProvider. These more complex scenarios are fully supported by the framework.

In general, you should write Data Providers for all of the kinds of data you want to be able to data bind on the server-side, and declare the data needs of each page element, and the framework will figure out how to supply all of the required data as efficiently as possible by calling the Data Provider the least number of times.

I would highly recommend making your Data Providers granular, ie each Data Provider provides only one type of data, and depends on 0 or more other types of data. This approach will avoid your application becomming overly complex and inneficient as your applications grows.

    internal class Person
    {
        public string Name { get; set; }
        public Address Address { get; set; }
    }
    internal class Address
    {
        public string Street { get; set; }
        public string City { get; set; }
        public string ZipCode { get; set; }
    }
    [IsDataProvider("people", typeof(IList))]
    internal class PersonListProvider : DataProvider
    {
        public PersonListProvider(IDataProviderDependenciesFactory dependencies)
            : base(dependencies) { }
        protected override void Supply(IRenderContext renderContext, IDataContext dataContext, IDataDependency dependency)
        {
            var people = new[]
            {
                new Person { Name = "Person 1", Address = new Address { Street = "1 Main St", City = "City", ZipCode = "12345" }},
                new Person { Name = "Person 2", Address = new Address { Street = "2 Main St", City = "City", ZipCode = "54321" }},
                new Person { Name = "Person 3", Address = new Address { Street = "3 Main St", City = "City", ZipCode = "99999" }},
            };
            dataContext.Set>(people);
        }
    }
    [IsDataProvider("person_address")]
    [SuppliesData(typeof(Address))]
    [NeedsData(typeof(Person))]
    internal class PersonAddressProvider : DataProvider
    {
        public PersonAddressProvider(IDataProviderDependenciesFactory dependencies)
            : base(dependencies) { }
        protected override void Supply(IRenderContext renderContext, IDataContext dataContext, IDataDependency dependency)
        {
            var person = dataContext.Get();
            dataContext.Set(person.Address);
        }
    }