Posts Tagged ‘.net framework’
The discussion on using BackgroundWorker here is good but I had to abandon the use of the WebClient class inside the upload object.
Doing async with the BackgroundWorker class (System.ComponentModel) is easy, but when I realized that async could also be done with the WebClient class (System.net) while the BackgroundWorker is executing I had to give it a try so that I could support cancelation. It works, but you have to follow the BackgroundWorker async pattern carefully.
In my case I created a Delivery class that has the responsibility of setting up the BackgroundWorker, staging ftp execution, and clean up. I have an Upload object that manages the async FTP upload separately . This Upload object is created when Delivery.Execute is called and then passed along to the BackgroundWorker.DoWork event hander, named InitDelivery, for execution. Here’s the code for InitDelivery:
Here is how it works:
1) The Upload object is retrieved from the e.Argument.
2) The Upload object is passed to a local field so that it’s internal async operation can be canceled if need be.
3) The method Upload.ExecuteAsync is called.
4) Next we wait for the ‘while(Upload.IsBusy)’ to compete. But you might ask why I am doing this if I am using an async in the Upload object? Here are the reasons:
- The BackgroundWorker is designed for managing long running, synchronous tasks so we need to mimic that pattern inside the BackgroundWorker.DoWork event handler.
- The Upload.IsBusy state is always set to false when the internal async operation finishes regardless of completion, cancelation, or exception.
- I need to use state from the Upload object in the BackgroundWorker.RunWorkerCompleted event handler.
5) The Upload object is passed to e.Result and the event handler exits.
The BackgroundWorker.RunWorkerCompleted event is wired to DeliveryFinish. Here is the code:
Here is how it works:
1) The Delivery.Error property is set from e.Error and the Upload object is retrieved from e.Result.
2) If the Upload object has an error then it is forwarded to the Delivery.Error property.
3) Perform any logging and clean up as necessary.
4) The Try/Finally block ensures that Delivery.IsFinished is always set to true.
Looks like the ‘Upload.IsBusy’ thread really hammers the processor. To remove that I’ve added a Thread.Sleep call that really dampens things down, and it does keep the transfer working.
That’s it for Part 1. In Part 2 I’ll look at the Upload object and cover a few highlights. Here is the link:
Like any type of design – software design has it’s trade offs. As example, if you componentize the process of binding and updating an object graph with a view you get great code reuse but if you step out-of-bounds you are usually stuck out in the code. But if you don’t componentize the process then your stuck with “copy/paste inheritance” which is another kind of madness in and of itself. So what to do? Good question. I don’t have the answer, but I think I have a few ideas. And that’s the point. There are no magic keys, no “golden hammers”, no CASE tools that leave you saying “I know Kung Fu!” Of course the hard part is knowing when your in this situation. For me it’s when I start telling my self “It takes an act of …” to get this done, or to work around. Here are a few things I have learned:
1) There is no one right way to solve a problem.
Have you found three methods of solving a problem? That’s okay, just make sure you give them a clear member name and you’ll be fine. If necessary just create a utility class, or better yet if you can use Microsoft .net 3.5 create a set of extension methods as necessary.
2) Keep the “have to” scenarios narrowly scoped yet flexible.
Have a required process to load controls into a UI framework? That’s fine, but don’t have the same component force other contracts on the control, and make sure you have several methods of being able to inject controls. For example, a required contract for loading UI controls could allow for using metadata, controllers/presenters or even configuration (if you really need it) to load the controls. You probably want to delegate everything else to the control.
3) Throw out that old code! (When you can …)
Over the course of a project you’ll more than likely come up with a new class or method to solve a similar problem that an older class or method couldn’t handle. Consider obsoleting the old code and extending the new code to handle necessary scenarios. Maintaining old code paths can be very frustrating and time consuming. Of course it depends on what the opportunity cost is. This often cannot be done in one release or update. Choose the right time to make the changes.
4) Overcome your complexity in the solution.
Most of us programmers love the puzzle solving in the process of software development. But sometimes the solutions are nightmare. So when you write that complicated solution to a problem there are at least two questions can be asked. First, has someone else solved this problem? And by that I mean not only another programmer but a software company. For example, there are better tools than StringBuilder for working with XML in the .net framework. (System.Xml.Linq) Is the solution “too big to fail”? Strongly consider breaking it up. Not only will the code base be easier to manage but you’ll have more options for code reuse that you may not have considered along the way.
5) Keep your code granular.
Your shower more than likely does not double as dishwasher. Tables usually don’t double well as chairs. Shoes don’t work well as gloves. And on and on. We should aspire to keep this in mind as we program. But this is not always easy. But if you can think of your code as individual parts of a digital assembly line and let every part play its role with utter simplicity. So more, no less. And besides – that’s how nature does it. We programmers could learn a lot from Biologists and Chemists.