Hi swin,
I'm sorry I neglected to make good on my promise to post my method. Deadlines are a killer :) Those deadlines also prevented me from implementing this *exactly* like I wanted to, but I had to settle for good enough.
The meat of this solution is in the EntityDataSourceEventAdapter:
using System;
using System.Collections.Generic;
using System.Text;
namespace SBRILD.Web.App_Code
{
public class EntityDataSourceEventAdapter
{
public void RegisterDataSource<D, P>(D ds, P provider)
where D : SBRILD.Web.Data.IDataSourceEvents, SBRILD.Web.Data.ILinkedDataSource
where P : SBRILD.Services.IComponentService
{
MessageAdapter<D, P> ma = new MessageAdapter<D, P>();
ma.RegisterIndividualDataSource(ds, provider);
ma.DataSourceMessageEvent += new MessageAdapter<D, P>.DataSourceMessageReport(DataSourceMessageReported);
}
void DataSourceMessageReported(Object sender, string message)
{
MessageReported(sender, message);
}
public delegate void MessageRaised(Object sender, String message);
public event MessageRaised MessageReported;
}
class MessageAdapter<D, P>
where D : SBRILD.Web.Data.IDataSourceEvents, SBRILD.Web.Data.ILinkedDataSource
where P : SBRILD.Services.IComponentService
{
//Service provider
private SBRILD.Services.IComponentService service;
private String messages = String.Empty;
/// <summary>
/// Register a datasource's Inserted and Updated events
/// </summary>
/// <param name="ds"></param>
/// <param name="provider"></param>
public void RegisterIndividualDataSource(D ds, P provider)
{
//Register Inserted and AfterInserted event handles
ds.Inserted += new System.Web.UI.WebControls.ObjectDataSourceStatusEventHandler(ds_Inserted);
//ds.AfterInserted += new SBRILD.Web.Data.LinkedDataSourceEventHandler(ds_AfterInserted);
//Register Updated and AfterUpdated event handlers
ds.Updated += new System.Web.UI.WebControls.ObjectDataSourceStatusEventHandler(ds_Updated);
//ds.AfterUpdated += new SBRILD.Web.Data.LinkedDataSourceEventHandler(ds_AfterUpdated);
//Register service provider
service = provider;
}
/// <summary>
/// Occurs when a DataSource's Inserted event is fired
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ds_Inserted(object sender, System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs e)
{
//Iterate through each of the service's processors
foreach (SBRILD.Services.ProcessorBase proc in service.ProcessorList)
{
//Get the result associated with this processor
SBRILD.Services.IProcessorResult result = proc.ProcessResult;
//Get each BrokenRulesList from the processor
foreach (KeyValuePair<Type, SBRILD.Entities.Validation.BrokenRulesList> kvp in result.BrokenRulesLists)
{
//Get each BrokenRule from the BrokenRulesList
foreach (SBRILD.Entities.Validation.BrokenRule br in kvp.Value)
{
//Report broken rule
//MessageEvent(br.Description.ToString());
messages += br.Description;
}
}
//Define an IWarningProcessorResult
SBRILD.Services.App_Code.IWarningProcessorResult warningResult = proc.ProcessResult as SBRILD.Services.App_Code.IWarningProcessorResult;
//If it exists
if (warningResult != null)
{
//Get each warning message in the list
foreach (String warning in warningResult.WarningList)
{
messages += warning;
}
}
}
//Handle any EntityNotValidExceptions
if (e.Exception != null && e.Exception.GetType() == typeof(SBRILD.Entities.EntityNotValidException))
{
e.ExceptionHandled = true;
}
if (messages != String.Empty)
{
DataSourceMessageEvent(sender, messages);
}
}
/// <summary>
/// Occurs when a DataSource's Updated event is fired
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ds_Updated(object sender, System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs e)
{
//Iterate through each of the service's processors
foreach (SBRILD.Services.ProcessorBase proc in service.ProcessorList)
{
//Get the result associated with this processor
SBRILD.Services.IProcessorResult result = proc.ProcessResult;
//Get each BrokenRulesList from the processor
foreach (KeyValuePair<Type, SBRILD.Entities.Validation.BrokenRulesList> kvp in result.BrokenRulesLists)
{
//Get each BrokenRule from the BrokenRulesList
foreach (SBRILD.Entities.Validation.BrokenRule br in kvp.Value)
{
//Report broken rule
//MessageEvent(br.Description.ToString());
messages += br.Description;
}
}
//Define an IWarningProcessorResult
SBRILD.Services.App_Code.IWarningProcessorResult warningResult = proc.ProcessResult as SBRILD.Services.App_Code.IWarningProcessorResult;
//If it exists
if (warningResult != null)
{
//Get each warning message in the list
foreach (String warning in warningResult.WarningList)
{
messages += warning;
}
}
}
//Handle any EntityNotValidExceptions
if (e.Exception != null && e.Exception.GetType() == typeof(SBRILD.Entities.EntityNotValidException))
{
e.ExceptionHandled = true;
}
if (messages != String.Empty)
{
DataSourceMessageEvent(sender, messages);
}
}
public delegate void DataSourceMessageReport(Object sender, String message);
public event DataSourceMessageReport DataSourceMessageEvent;
}
}
//END
I'm using the ServiceLayer model. Even more specifically, the processor results returned from the service's execution implement a custom interface (IWarningProcessorResult) in addition to extending nettier's GenericProcessorResult. The idea here is that I have a number of processors that modify entities that would otherwise be invalid. These modifications prevent some entities from being flagged as invalid (and thus providing information in the BrokenRulesList), but I still need to notify the user that the adjustments were made (an example here is a percentage entity that is increased by, say, 7%, and this increase makes the sum of some related entities = 103%...the processor would reduce the 7% to 4% so the total was 100%, and then inform the user of the automatic reduction) . That's where the IWarningProcessorResult came in:
/// <summary>
/// The interface that processors implement if they report warnings in addition to the
/// BrokenRules reported by entity validation
/// </summary>
public interface IWarningProcessorResult
{
/// <summary>
/// List of strings describing each warning
/// </summary>
List<String> WarningList { get;}
}
//END
The Inserted and Updated event handlers iterate through the BrokenRulesLists and WarningLists and fires an event reporting the messages. I've hooked up to that event in the asp page (also, here's where I register the DataSources):
private void RegisterDataSourceEventHandlers()
{
//Create new EntityDataSourceEventAdapter
SBRILD.Web.App_Code.EntityDataSourceEventAdapter edsa = new SBRILD.Web.App_Code.EntityDataSourceEventAdapter();
//Register data sources
edsa.RegisterDataSource(DefaultDistributionDataSource, DefaultDistributionDataSource.Provider as SBRILD.Services.IComponentService);
edsa.RegisterDataSource(SalaryDataSource, SalaryDataSource.Provider as SBRILD.Services.IComponentService);
//Register event handler will write messages to page that that will
edsa.MessageReported += new SBRILD.Web.App_Code.EntityDataSourceEventAdapter.MessageRaised(edsa_MessageReported);
}
/// <summary>
/// Handle messages sent from the EntityDataSourceEventAdapter
/// </summary>
/// <param name="message"></param>
void edsa_MessageReported(Object sender, string message)
{
DataSourceEventsText = message;
}
I wish I had time to make the implementation more generic, but then again, I wish I had more time for alot of things :) I'm absolutely positive there are better ways to accomplish this, but alas, I needed a concrete implementation and fast. Please do let me know if there's anything that doens't make sense or isn't helpful.
Cheers,
Evan