I have a system which fundamentally is used to resolve exceptions and output a CSV on demand which details every resolved item. Each day, there will be new exceptions which need to be dealt with. I have a POST method for this in my controller:
[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
// resolve database records...
return RedirectToAction("Index", "Exceptions");
}
I have had a new requirement however, the user wants the system to identify when the last outstanding has been resolved and then automatically output the CSV to the file share, rather than having to go and do this manually.
I firstly created a method for checking whether or not that was the last exception, and called this WasLastException(); I knew that I could just wrap this in an IF statement and on true call a method I have called OutputMasterFileCsv(); but before doing this I thought I would try out delegates/events for the first time which has led me to a similar result but has also raised a few questions.
Some background to my application
This is an Entity Framework Code First MVC web application that is making use of using Unity DI, I have wrapped all my repository calls in an ProcessDataService class in my core layer, which has an interface IProcessDataService that is being registered with Unity.
This is how I have tried to add my event:
Controller's constructor
public ExceptionsController(IProcessDataService service)
{
_service = service; //publisher
//event for delegate
OutputService outputService = new OutputService(_service); //subscriber
_service.LastException += outputService.OnLastException;
}
Output Service
public void OnLastException(object source, EventArgs e)
{
// output the CSV
}
Process Data Service
public delegate void LastExceptionEventHandler(object source, EventArgs args);
public class ProcessDataService : IProcessDataService
{
private readonly IExceptionRepository _exceptionRepository;
public ProcessDataService(IExceptionRepository evpRepo)
{
_exceptionRepository = evpRepo;
}
public event LastExceptionEventHandler LastException;
public void OnLastException()
{
if (LastException != null)
LastException(this, EventArgs.Empty);
}
}
New Resolve method in the Controller
[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
// resolve database records...
if(_service.WasLastException())
{
//raise the event
_service.OnLastException();
}
return RedirectToAction("Index", "Exceptions");
}
This all works well, however I feel like I am not using delagates and events in the right place here somehow, Instead of calling the OnLastException() above and making use of the event, why wouldn't I just simply call _service.OutputMasterFileCsv(); which is already located in my ProcessDataService class?
I believe this has something to do with loose coupling but I dont fully understand what the benefits of this actually are, or am I completely off the mark with all this...?
I thought I would give it ago anyway while I had the chance and hopefully learn something new. If anyone with abit more experience could step in and provide some guidance it would be greatly appreciated as I am a little lost now.
As you are correctly pointing out, using events in this way does not make much sense:
if(_service.WasLastException())
{
//raise the event
_service.OnLastException();
}
You can fix this by making IProcessDataService expose a ResolveException action, and moving the resolving logic from the controller to the service:
[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
// make needed preparations...
_service.ResolveException(...prepared parameters...);
return RedirectToAction("Index", "Exceptions");
}
Then, inside the ProcessDataService.ResolveException method check
if you are currently processing the last exception, and raise the LastException event.
public class ProcessDataService : IProcessDataService
{
//...
public ResolveException(...prepared parameters...) {
// resolve an exception and set lastException
if(lastException) {
this.OnLastException();
}
}
// notice the private modifier
private void OnLastException()
{
if (LastException != null)
LastException(this, EventArgs.Empty);
}
}
This way the data processing service simply notifies the outside world when the last exception is processed. The service has no idea if anyone cares or does something when this happens. The controller knows even less. Only the output service contains processing logic for last exceptions.
With that said, the real power of events lies in the fact that there can be many subscribers, with each subscriber performing its own tasks without knowing anything about the other subscribers. So, you could for instance add another event handler to say, send an email to a supervisor saying that all the exceptions for the day have been resolved.
What matters is that in this case you would not need to modify the controller or other services to account for this newly introduced email sending functionality.
You have decoupled the controller from the service and service from storage. That is fine. But I don't really understand the sense of the event LastException in the ProcessDataService. This is already decoupled by interface IProcessDataService, why to use event?
Another think I don't understand is where is the last exception?
If you want to decouple outputService from ProcessDataService, you can do it like:
public ProcessDataService(IExceptionRepository evpRepo, IOutputService outputService)
{
_exceptionRepository = evpRepo;
_outputService = _outputService;
}
public void ProcessLastException()
{
_outputService.Command() //or whatever suitable name you for your method
}
And in controller:
if(_service.WasLastException())
{
//call service
_service.ProcessLastException();
}
Or even more simple add some method for processing last exception to IProcessDataService.
There are more ways how to inject dependency. You have injected the dependency into constructor and that is why, you don't need the event for decoupling.
Related
So im trying to implement a multi-site server-side blazor application that has two services implemented as singletons like this:
services.AddSingleton<MQTTService>();
services.AddHostedService(sp => sp.GetRequiredService<MQTTService>());
services.AddSingleton<DataCollectorService>();
services.AddHostedService(sp => sp.GetRequiredService<DataCollectorService>());
The MQTT Service is connecting to the broker and managing the subscriptions and stuff, while the DataCollectorService subscribes to an event from the MQTT Service to be notified when a new message arrives. The business logic with the received data is then happening within the DataCollectorService, stuff like interpreting the topic and the payload of the mqtt message. If its valid, the DataCollectorService stores the Data in a (example) global static class:
if (mqtt.IsTopic(topic, MQTTService.TopicDesc.FirstTopic))
{
if(topic.Contains("Data1"))
{
if(topic.Contains("Temperature"))
{
DataCenter.Data1.Temperature= Encoding.UTF8.GetString(message, 0, message.Length);
}
}
}
The DataCenter is just a static class in the namespace:
public static class DataCenter
{
public static DataBlock Data1 = new DataBlock();
public static DataBlock Data2 = new DataBlock();
public static string SetMode;
public class DataBlock
{
public string Temperature { get; set; }
public string Name{ get; set; }
}
}
My Goal with this approach is that every different page in my project can just bind these global variables to show them.
The first problem that occurs then is that obviously the page is not aware of the change if the DataCollectorService updates a variable. Thats why i implemented a notifying event for the pages, which can then call StateHasChanged. So my examplePage "Monitor" wants to just show all these values and injects the DataCollectorService:
#page "/monitor"
#inject DataCollectorService dcs
<MudText>DataBlock Data1: #DataCenter.Data1.Temperature/ Data2: #DataCenter.Data2.Temperature</MudText>
#code
{
protected override void OnInitialized()
{
dcs.OnRefresh += OnRefresh;
}
void OnRefresh()
{
InvokeAsync(() =>
{
Console.WriteLine("OnRefresh CALLED");
StateHasChanged();
});
}
}
This actually works, but adds a new problem to the table, everytime i switch to my monitor site again a NEW OnRefresh Method gets hooked to the Action and that results in multiple calls of "OnRefresh". I find this behaviour rather logical, cuz i never delete an "old" OnRefresh Method from the Action when I'm leaving the site, cuz i dont know WHEN i leave the site.
Thinking about this problem i came up with a solution:
if (!dcs.IsRegistered("monitor"))
{
dcs.OnRefresh += OnRefresh;
dcs.RegisterSubscription("monitor");
}
I wrapped the action subscription with a system that registers token whenever the handler is already correctly assigned. the problem now: the variables on the site dont refresh anymore!
And thats where i'm not sure how to understand whats going on anymore. If i keep it like in the first example, so just adding dcs.OnRefresh += OnRefresh; and letting it "stack up", it actually works - because there is always a "new" and "correctly" bound method which, in my limited understanding, has the correct context.
if i forbid this behaviour i only have an somehow "old" method connected which somehow cant execute the StateHasChanged correctly. But i dont know why.
I'm not sure if i could:
"Change" the context of the Invoke Call so that StateHasChanged works again?
Change the way I register the Action Handling method
I'm additionally confused as to why the first way seems to call the method multiple times. Because if its not able to correctly call StateHasChanged() in the old method, why can it be called in the first place?
I would very much appreciate some input here, googling this kind of stuff was rather difficult because i dont know the exact root of the problem.
Not only do you have multiple calls, you also have a memory leak. The event subscription will prevent the Monitor object to be collected.
Make the page IDisposable:
#page "/monitor"
#inject DataCollectorService dcs
#implements IDisposable
...
#code
{
protected override void OnInitialized()
{
dcs.OnRefresh += OnRefresh;
}
...
public void Dispose()
{
dcs.OnRefresh -= OnRefresh;
}
}
My DAL doesn't handle exceptions and it will be propagated up to the calling method in the presenter classes where the exception will be handled.
I'm using a single handler called ExecutAction(Action action) so I'm catching exceptions in one place rather than repeating in every method.
At the moment, I'm not logging errors. Just alert the user for an action and try to keep the system alive if possible.
When showing messages to users, Presenters will use a static class called MessagingService. (ShowErrorMessage()). So that I can customize all massage boxes in one place.
private void Search()
{
ExecutAction(() =>
{
var info = _DataService.GetByACNo(_model.AccountNumber);
if (info != null)
{
_Model = info ;
this.SetViewPropertiesFromModel(_Model, _View);
}
else
{
MessageBox.Show ("Bank account not found");
}
});
}
private void ExecutAction(Action action)
{
try
{
action();
}
catch (NullReferenceException e) { MessagingService.ShowErrorMessage(e.Message); }
catch (System.Data.SqlTypes.SqlTypeException e) { MessagingService.ShowErrorMessage(e.Message); }
catch (System.Data.SqlClient.SqlException e) { MessagingService.ShowErrorMessage(e.Message); }
}
}
Should I include general exception handler to this, to be able to handle any unforeseen exceptions?
Also could you show me a better way to handle showing messages than using a static?
Does use of lambda statements in every method call (ExecutAction(() =>) degrade code readability?
When showing user messages how to show a custom message like "Check the server connection" etc. first and then if the user wants more information (like StackTrace / technical details) he /she could press a button like More Info which is in the MessageBox dialog?
I agree with jeffrey about trying to incorporate IoC for your message service. You could define an abstract base presenter class that has a dependency on an interface for your message service. The base class would be responsible for handling the delegate execution + exception logging.
public interface IMessageService
{
void ShowErrorMessage(Exception e);
}
public abstract class PresenterBase
{
private readonly IMessageService _messageService;
public PresenterBase(IMessageService messageService)
{
this._messageService = messageService;
}
protected void ExecuteAction(Action action)
{
try
{
action();
}
catch (Exception e) { this._messageService.ShowErrorMessage(e); }
}
}
public class SearchPresenter: PresenterBase
{
public SearchPresenter(IMessageService messageService)
: base(messageService)
{
}
public void Search()
{
this.ExecuteAction(() =>
{
//perform search action
});
}
}
Regarding your question about catching all exeptions. Unless you are doing something special for specific types of exceptions, I would suggest just handling all the same. The example I provided passes the exception to the message service so that the formatting specifics can be handled by your message service.
If you have not yet incorporated any sort of IoC container, you can always start by using the interface injection and then passing the instance explicitly from the child class constructor.
public class SearchPresenter: PresenterBase
{
public SearchPresenter()
: base(new SomeMessageService())
{
}
...
}
This is at least removes the static dependency and is not too dificult to swap out later if you ever introduce an IoC container.
I think your approach is good enough for your work. Wrapping logics by ExecuteAction is an acceptable way to me. As another option, I might use AOP for centralized exception handling in practice.
Also, I might use a MessagingService resolved from dependency injection container rather than a static one.
Regarding how to display the error, that's totally depend on your business purpose. For example, you could simply log the error and tell the user "something's wrong", or show them the complete stacktrace including the environment information so they could simply copy & paste in the email.
I've done alot of research, including here on SO, and I can't seem to find clear direction. I currently have an ASP.NET MVC3 application, with a service layer that sits on top of a repository.
In my service layer, I have functions such as:
public class MyService{
public void CreateDebitRequest(int userId, int cardId, decimal Amount, .... )
{
//perform some sort of validation on parameters, save to database
}
public void CreateCreditRequest(.....)
}
//perform some sort of validation on parameters, save to database
}
public void CreateBatchFile()
{
//construct a file using a semi-complex process which could fail
//write the file to the server, which could fail
}
public PaymentTransaction ChargePaymentCard(int paymentCardId, decimal amount)
{
//validate customer is eligible for amount, call 3rd party payments api call,
//...save to database, other potential failures, etc.
}
}
I've seen people say that parameter validation isn't very exceptional, and so throwing an exception is not very fitting. I also don't love the idea of passing in an out paramater, such as a string, and checking for an empty value. I've considered implementing a ValidationDictionary class, and making it a property of any given service class (it would contain an IsValid boolean, and a List of error messages, and could be checked after any given function call in the service layer to see how things went). I could check the ValidationDictionary status after running any given function:
var svc = new MyService();
svc.CreateBatchFile();
if (svc.ValidationDictionary.IsValid)
//proceed
else
//display values from svc.ValidationDictionary.Messages...
The thing I don't like about this is that I would have to update it for every service layer function call, to avoid having it retain old values (if I chose not to use it for many or most functions, one would still expect it to have a meaningful or null value after running any given function). Another thing I've considered is passing in the ValidationDictionary for each function call that might have detailed validation information, but then I am back to using an out parameter...
Do any of you have recommendations? I can't seem to figure out any clean way of doing this. Sometimes returning null for a function is enough information, but sometimes I'd like a little more validation information passed back to the caller. Any advice would be appreciated!
Edit to clarify:
My service layer is not aware that it is an MVC application that is consuming it. The service layer just has certain public functions such as CreateBatchFile() or AddDebitRequest(). Sometimes returning null is enough for the consumer (in this case a controller, but could be something else) to know what happened, and sometimes the consumer would like some more information from the service layer (maybe to pass along to ModelState if the consumer is a controller). How do I bubble this up from the service layer itself?
This is what I do. Have a class for your validation, and instead of passing parameters pass a view model. So in your case something like this, where ValidationResult is just a simple class w/ MemberName and ErrorMessage properties:
public class DebitRequestValidator{
public IEnumerable<ValidationResult> Validate(DebitRequestModel model){
//do some validation
yield return new ValidationResult {
MemberName = "cardId",
ErrorMessage = "Invalid CardId."
}
}
}
Then create a controller extension method to copy these validation results to the model state.
public static class ControllerExtensions
{
public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable<ValidationResult> validationResults)
{
if (validationResults == null) return;
foreach (var validationResult in validationResults)
{
modelState.AddModelError(validationResult.MemberName, validationResult.ErrorMessage);
}
}
}
Then in your controller do something like
[HttpPost]
public ActionResult DebitRequest(DebitRequestModel model) {
var validator = new DebitRequestValidator();
var results = validator.Validate(model);
ModelState.AddModelErrors(results);
if (!ModelState.IsValid)
return View(model)
//else do other stuff here
}
Then in your view you can display errors like normal.
#Html.ValidationMessageFor(m => m.CardId)
I used a system where it was passing an array of messages (or collection of classes), each element had codes, descriptions, friendly messages. We used to simply check if anything was there. It worked great between UI and another "service" layer, all exception were caught nicely, they were translated into these validation rules...just an idea
Use ViewModel objects that are passed between the Views and the Controller action methods. The ViewModel objects can handle Validation by a Validate(ValidationDictionary validationDictionary) method.
The controller will have to call the Validate method on ViewModel object before calling any method in the service layer. This should only be necessary for http POST actions.
Your views will then have to display validation messages.
This solution requires that the viewmodel objects are passed between the controller action and the view, but nowadays that is mostly handled by the ModelBinder in MVC.
Your controller (http post) actions will look something like this:
[HttpPost]
public ActionResult Foo(BarViewModel viewModel)
{
viewModel.Validate(ValidationDictionary);
if (!ModelState.IsValid)
{
return View(viewModel);
}
// Calls to servicelayer
}
Your Validate method in your ViewModel will look like this:
public void Validate(ValidationDictionary validationDictionary)
{
if (SomeProperty.Length > 30)
{
validationDictionary.AddError("SomeProperty", "Max length is 30 chars");
}
}
If you're just doing ViewModel Validation, FluentValidation is an excellent library.
If you're wanting to include business validation as feedback to the user, you could use the adapter pattern, it'll give you what you want.
Create an interface (IValidationDictionary or something similar). This interface would define an AddError method and would be passed to your service in order to add error messages.
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
}
Create a ModelStateAdapter for your mvc application.
public class ModelStateAdapter : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateAdapter(ModelStateDictionary modelState)
{
_modelState = modelState;
}
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
}
Your service calls that need validation would require the IValidationDictionary
public class MyService
{
public void CreateDebitRequest(int userId, int cardId, decimal Amount, .... , IValidationDictionary validationDictionary)
{
if(userId == 0)
validationDictionary.AddError("UserId", "UserId cannot be 0");
}
}
You would then have a dependency on IValidationDictionary but not on MVC which would also make your solution testable.
If you needed to implement the services in an app that didn't have a ModelStateDictionary, you would just implement the IValidationDictionary interface on a class used for holding your errors.
Controller example:
public ActionResult Test(ViewModel viewModel)
{
var modelStateAdapter = new ModelStateAdapter(ModelState);
_serviceName.CreateDebitRequest(viewModel.UserId, viewModel.CardId, ... , modelStateAdapter);
if(ModelState.IsValid)
return View("Success")
return View(viewModel);
}
Pro's of this approach:
No dependency on the calling libraries
It's possible to mock the IValidationDictionary for tests.
Con's of this approach:
You need to pass IValidationDictionary to every method that you want to do validation on that's going to be returned to the user.
Or
you need to initialise the service's validation dictionary (if you decide to have IValidationDictionary as a private field), in each controller action you want to validate against.
I have a service that reads all emails as they get received in a specific mailbox. The issue is that based on what the email contains we have to do one or many actions. I currently have the mess below. I've shortened it quite a bit. The actual application currently has far more corner cases.
var email = new Email { Body = "Some random email body text..." };
if(email.Body.StartsWith("A"))
{
// Requires a dependency on INotifier
Console.WriteLine("Notifying administrator");
}
if (email.Body.StartsWith("B"))
{
// Requires a dependency on IParser and IRepository
Console.WriteLine("Parsing email and adding to database");
}
if (email.Body.EndsWith("C"))
{
// Requires a dependency on ISender and INotifier
Console.WriteLine("Forwarding email and notifying administrator");
}
if (email.Body.EndsWith("C"))
{
// Requires a dependency on INotifier
Console.WriteLine("Ignoring email");
}
Essentially, if a criteria is met then an associating action must get executed using one or more dependencies. These dependencies are something I'd like to inject in the constructor.
I've thought of creating something like this:
public class AdministratorNotififerCriteria : ICriteria
{
private readonly INotifier _notifier;
public AdministratorNotififerCriteria(INotifier notifier)
{
_notifier = notifier;
}
private void Execute()
{
_notifier.Notify();
}
public void CheckSatisfaction(Email email)
{
if(email.Body.StartsWith("A"))
Execute();
}
}
The bottom line is that I wish to make composable commands. So when I add another criteria down the line then all I have to do is inherit from ICriteria (or whatever) and let the application figure it out.
Is there a name for all of this?
I currently have a consumer that resembles this.
public class EmailConsumer
{
private readonly IEnumerable<ICriteria> _criterias;
// Criterias are found and injected with Windsor from all classes inheriting the ICriteria interface
public EmailConsumer(IList<ICriteria> criterias)
{
_criterias = criterias;
}
public void Consume(IList<Email> emails)
{
foreach(var criteria in _criterias)
{
foreach(var email in emails)
{
criteria.CheckSatisfaction(email);
}
}
}
}
Edit
Thanks for the replies, IAbstract and djna. I now understand what the strategy and CoR pattern do and thinking about which is more appropriate is proving that I don't understand enough of my current problem.
The way I understand it is that CoR is greedy and whoever can take responsibility will execute and proceed to the next object to be consumed. On the other hand, there doesn't seem to be anything stopping from looping between strategies that says "Hey! I can consume this request properly so don't worry about it".
This seems like a variation of Chain of responsibility with possibly some extra logic for dealing with non-exclusive cases - what do you intend should happen if the Body starts with "A" and ends with "C"?
One idea in Chain of Resposibility is that there's no need for a huge dispatching if/else chain. Instead you just offer the email to some ICriteria implementatio, and they have responsibility either to process or pass on to the next candidate.
#djna suggests a variation of the CoR pattern. I don't completely disagree. It seems more like this example of the Strategy Pattern.
We have an old Silverlight UserControl + WCF component in our framework and we would like to increase the reusability of this feature. The component should work with basic functionality by default, but we would like to extend it based on the current project (without modifying the original, so more of this control can appear in the full system with different functionality).
So we made a plan, where everything looks great, except one thing. Here is a short summary:
Silverlight UserControl can be extended and manipulated via ContentPresenter at the UI and ViewModel inheritance, events and messaging in the client logic.
Back-end business logic can be manipulated with module loading.
This gonna be okay I think. For example you can disable/remove fields from the UI with overriden ViewModel properties, and at the back-end you can avoid some action with custom modules.
The interesting part is when you add new fields via the ContentPresenter. Ok, you add new properties to the inherited ViewModel, then you can bind to them. You have the additional data. When you save base data, you know it's succeeded, then you can start saving your additional data (additional data can be anything, in a different table at back-end for example). Fine, we extended our UserControl and the back-end logic and the original userControl still doesn't know anything about our extension.
But we lost transaction. For example we can save base data, but additional data saving throws an exception, we have the updated base data but nothing in the additional table. We really doesn't want this possibility, so I came up with this idea:
One WCF call should wait for the other at the back-end, and if both arrived, we can begin cross thread communication between them, and of course, we can handle the base and the additional data in the same transaction, and the base component still doesn't know anything about the other (it just provide a feature to do something with it, but it doesn't know who gonna do it).
I made a very simplified proof of concept solution, this is the output:
1 send begins
Press return to send the second piece
2 send begins
2 send completed, returned: 1
1 send completed, returned: 2
Service
namespace MyService
{
[ServiceContract]
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1
{
protected bool _sameArrived;
protected Piece _same;
[OperationContract]
public Piece SendPiece(Piece piece)
{
_sameArrived = false;
Mediator.Instance.WaitFor(piece, sameArrived);
while (!_sameArrived)
{
Thread.Sleep(100);
}
return _same;
}
protected void sameArrived(Piece piece)
{
_same = piece;
_sameArrived = true;
}
}
}
Piece (entity)
namespace MyService
{
[DataContract]
public class Piece
{
[DataMember]
public long ID { get; set; }
[DataMember]
public string SameIdentifier { get; set; }
}
}
Mediator
namespace MyService
{
public sealed class Mediator
{
private static Mediator _instance;
private static object syncRoot = new Object();
private List<Tuple<Piece, Action<Piece>>> _waitsFor;
private Mediator()
{
_waitsFor = new List<Tuple<Piece, Action<Piece>>>();
}
public static Mediator Instance
{
get
{
if (_instance == null)
{
lock (syncRoot)
{
_instance = new Mediator();
}
}
return _instance;
}
}
public void WaitFor(Piece piece, Action<Piece> callback)
{
lock (_waitsFor)
{
var waiter = _waitsFor.Where(i => i.Item1.SameIdentifier == piece.SameIdentifier).FirstOrDefault();
if (waiter != null)
{
_waitsFor.Remove(waiter);
waiter.Item2(piece);
callback(waiter.Item1);
}
else
{
_waitsFor.Add(new Tuple<Piece, Action<Piece>>(piece, callback));
}
}
}
}
}
And the client side code
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
Client c1 = new Client(new Piece()
{
ID = 1,
SameIdentifier = "customIdentifier"
});
Client c2 = new Client(new Piece()
{
ID = 2,
SameIdentifier = "customIdentifier"
});
c1.SendPiece();
Console.WriteLine("Press return to send the second piece");
Console.ReadLine();
c2.SendPiece();
Console.ReadLine();
}
}
class Client
{
protected Piece _piece;
protected Service1Client _service;
public Client(Piece piece)
{
_piece = piece;
_service = new Service1Client();
}
public void SendPiece()
{
Console.WriteLine("{0} send begins", _piece.ID);
_service.BeginSendPiece(_piece, new AsyncCallback(sendPieceCallback), null);
}
protected void sendPieceCallback(IAsyncResult result)
{
Piece returnedPiece = _service.EndSendPiece(result);
Console.WriteLine("{0} send completed, returned: {1}", _piece.ID, returnedPiece.ID);
}
}
}
So is it a good idea to wait for another WCF call (which may or may not be invoked, so in a real example it would be more complex), and process them together with cross threading communication? Or not and I should look for another solution?
Thanks in advance,
negra
If you want to extend your application without changing any existing code, you can use MEF that is Microsoft Extensibility Framework.
For using MEF with silverlight see: http://development-guides.silverbaylabs.org/Video/Silverlight-MEF
I would not wait for 2 WCF calls from Silverlight, for the following reasons:
You are making your code more complex and less maintainable
You are storing business knowledge, that two services should be called together, in the client
I would call a single service that aggreagated the two services.
It doesn't feel like a great idea to me, to be honest. I think it would be neater if you could package up both "partial" requests in a single "full" request, and wait for that. Unfortunately I don't know the best way of doing that within WCF. It's possible that there's a generalized mechanism for this, but I don't know about it. Basically you'd need some loosely typed service layer where you could represent a generalized request and a generalized response, routing the requests appropriately in the server. You could then represent a collection of requests and responses easily.
That's the approach I'd look at, personally - but I don't know how neatly it will turn out in WCF.