I'm designing a composite WPF/MVVM application using Prism patterns. I've read the Developer's Guide to Microsoft Prism Library 5.0 for WPF and I am familiar with most of the patterns described.
My application's modules will consist of a number of binaries (dll-s) and some of them will include a shared library, which will define public interfaces to MVVM models, event classes for event aggregator and services implemented by that module. Other modules would be able to reference such a library and work with its models, events and services through public interfaces and IoC.
Let's say ModuleA.Shared shared library includes a public interface for its SampleModel and SampleService, which performs work with SampleModel:
namespace ModuleA.Shared
{
interface ISampleModel
{
int SampleProp01 { get; set; }
int SampleProp02 { get; set; }
}
interface ISampleService
{
ISampleModel GetSampleModelInstance();
void SaveSampleModelInstance(ISampleModel obj);
}
}
Now say ModuleB (in a non-shared binary) uses ModuleA's public library:
namespace ModuleB.Engine
{
class SampleClass
{
void SampleMethod()
{
ModuleA.Shared.ISampleService srvc = SomeIoCContainer.Resolve<ModuleA.Shared.ISampleService>();
ModuleA.Shared.ISampleModel obj = srvc.GetSampleModelInstance();
// Do some work on obj...
srvc.SaveSampleModelInstance(obj);
}
}
}
Okay, now let's say ModuleB is developed and mantained by a third-party (like a third-party plugin). At some point in time I add a new property to ModuleA.Shared.ISampleModel:
namespace ModuleA.Shared
{
interface ISampleModel
{
int SampleProp01 { get; set; }
int SampleProp02 { get; set; }
int NewProp { get; set; } // <-- New property
}
/* ... */
}
The final user upgrades my application, so the old ModuleA's binaries get replaced with the new ones. ModuleB is distributed by a third-party and its binaries stay the same.
Since ModuleA and ModuleB are now compiled with different versions of ModuleA.Shared.ISampleModel, I assume IoC resolving will not succeed and the application will end in an exception.
What I am asking is what are the good practices / patterns for resolving this kind of issuses? How to make some modules upgradable without breaking the support for third-party modules which depend on them and were built with an older version of their shared libraries?
This is completely independent of whether you use prism or not. You're providing a plugin api (through the use of prism's module disconvery), and you have to plan for versioning your api.
First of all, once a version of the api is released, it's frozen. You cannot ever touch it (unless you want your third parties to recompile everything, making them and your customers unhappy, to say the least).
Instead of changing the api, release a new version of it:
interface ISampleModelV1
{
int SampleProp01 { get; set; }
int SampleProp02 { get; set; }
}
becomes
interface ISampleModelV2
{
int SampleProp01 { get; set; }
int SampleProp02 { get; set; }
int NewProp { get; set; } // <-- New property
}
A third party can then decide to either continue to use ISampleModelV1 or switch to ISampleModelV2 if they need NewProp. Your app, of course, will have to support both of them.
As this gets ugly sooner or later as the amount of api versions increases, you might want to deprecate the old ones, e.g. if your app goes from 2.5 to 3.0, you could remove support for api 1.x... be sure to communicate these decisions to customers and third parties early enough, though.
BTW:
Challenges Not Addressed by Prism
[...] Application versioning
Related
I have a C# Web API project which has a Product class:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
and the following method to get a Product by it's Id:
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
Say I now have 10 different C# projects (i.e. not in the same solution, and a mixture of Windows Forms, Console, MVC etc) that all want to call this method and get a Product. I want to reduce the need for all 10 separate projects to have to have a class file for a Product object which is just duplicating the same structure, and also avoid using a class library DLL that is added to each project, is this possible somehow?
I know when I've previously used web services in .NET (these were the original services that created a WSDL file, and also WCF services), Visual Studio (I think) automatically created these classes behind the scenes based on the WSDL information which meant you could just consume a service and not have to worry about hand crafting each object yourself.
Is this possible to do in a Web API environment?
At work I've got thrown into developing a legacy enterprice application, that still is under production and stalled for the last few months because of bad design and instability.
So we've started using EF5 and applying some design patterns / layers to our application.
What I'm struggling to understand is: what exactly should the Service Layer do in our case? Would it be over-architecturing or would it provide some benefits without adding unneccesary comlexity?
Let's show you what we've got so far:
we've introduced EF (Code First with POCOs) to map our legacy database (works reasonably well)
we've created repositories for the most stuff we need in our new Data Layer (specific implementations, I don't see any kind of benefit regarding seperation of concern using generic repos..)
Now in the specific case it is about calculating prices for an article - either by getting a price from an arcile directly or from the group the article is in (if there is no price specified). It's getting a lot more complex, because there also are different pricelists involved (depending on the complete value of the order) and depending on the customer who also can have special prices etc.
So my main question is: who is responsible for getting the correct price?
My thoughts are:
The order has to know of the items it consists of. Those items on the other hand have to know what their price is, but the order must not know of how to calculate the item's price, just that it has to summarize their costs.
Excert of my code at the moment:
ArticlePrice (POCO, Mappings soon to be swapped by Fluid API)
[Table("artikeldaten_preise")]
public class ArticlePrice : BaseEntity
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("einheit")]
public int UnitId { get; set; }
[ForeignKey("UnitId")]
public virtual Unit Unit { get; set; }
[Column("preisliste")]
public int PricelistId { get; set; }
[ForeignKey("PricelistId")]
public virtual Pricelist Pricelist { get; set; }
[Column("artikel")]
public int ArticleId { get; set; }
[ForeignKey("ArticleId")]
public virtual Article Article { get; set; }
public PriceInfo PriceInfo { get; set; }
}
Article Price Repository:
public class ArticlePriceRepository : CarpetFiveRepository
{
public ArticlePriceRepository(CarpetFiveContext context) : base(context) {}
public IEnumerable<ArticlePrice> FindByCriteria(ArticlePriceCriteria criteria)
{
var prices = from price in DbContext.ArticlePrices
where
price.PricelistId == criteria.Pricelist.Id
&& price.ArticleId == criteria.Article.Id
&& price.UnitId == criteria.Unit.Id
&& price.Deleted == false
select price;
return prices.ToList();
}
}
public class ArticlePriceCriteria
{
public Pricelist Pricelist { get; set; }
public Article Article { get; set; }
public Unit Unit { get; set; }
public ArticlePriceCriteria(Pricelist pricelist, Article article, Unit unit)
{
Pricelist = pricelist;
Article = article;
Unit = unit;
}
}
PriceService (does have a horriffic code smell...)
public class PriceService
{
private PricelistRepository _pricelistRepository;
private ArticlePriceRepository _articlePriceRepository;
private PriceGroupRepository _priceGroupRepository;
public PriceService(PricelistRepository pricelistRepository, ArticlePriceRepository articlePriceRepository, PriceGroupRepository priceGroupRepository)
{
_pricelistRepository = pricelistRepository;
_articlePriceRepository = articlePriceRepository;
_priceGroupRepository = priceGroupRepository;
}
public double GetByArticle(Article article, Unit unit, double amount = 1, double orderValue = 0, DateTime dateTime = new DateTime())
{
var pricelists = _pricelistRepository.FindByDate(dateTime, orderValue);
var articlePrices = new List<ArticlePrice>();
foreach (var list in pricelists)
articlePrices.AddRange(_articlePriceRepository.FindByCriteria(new ArticlePriceCriteria(list, article, unit)));
double price = 0;
double priceDiff = 0;
foreach (var articlePrice in articlePrices)
{
switch (articlePrice.PriceInfo.Type)
{
case PriceTypes.Absolute:
price = articlePrice.PriceInfo.Price;
break;
case PriceTypes.Difference:
priceDiff = priceDiff + articlePrice.PriceInfo.Price;
break;
}
}
return (price + priceDiff) * amount;
}
public double GetByPriceGroup(PriceGroup priceGroup, Unit unit)
{
throw new NotImplementedException("not implemented yet");
}
//etc. you'll get the point that this approach might be completely WRONG
}
My final questions are:
How do I correctly model my problem? Is it correct, that I am on my way of overarchitecturing my code?
How would my Service Layer correctly look like? Would I rather have a ArticlePriceService, an ArticleGroupPriceService, etc.? But who would connect that pieces and calculate the correct price? Would that e.g. be the responsibility of an OrderItemService that has a method "GetPrice"? But then again the orderItemService would have to know about the other services..
Please try to provide me with possible solutions regarding architecture, and which object/layer does what.
Feel free to ask me additional questions if you need more info!
You did present a simple scenario which the Repository itself might be sufficient.
Do you have more repositories?
Do you expect you application to grow, and have more repositories in use?
Having a service layer that abstract the data layer is recommended and in use by most of the applications/examples that I have seen, and the overhead is not that significant.
One reason for using services might pop-up when you would like to fetch data from several different repositories, and then perform some kind of aggregation / manipulations on the data.
A Service layer would then provide the manipulation logic, while the service consumer would not have to deal with several different repositories.
You should also think of situations where you might want to have more then one entity changed in one transaction (Meaning - more than one repository), and saving the changes to the DB only when all update actions where successful.
That situation should imply using the Unit Of Work Pattern, and probably will conclude the use of a Service Layer, to enable proper unit-testing.
When i started with objects and architecture, my main problem was to give a good name to classes.
To me, it seems your service should be called "ShopService" (or something equivalent). Then your method GetByArticle, should be nammed GetPriceByArticle.
The idea of changing the name of the service for something bigger than just the price would be more meaningfull and would also address other issues (like your OrderPriceService you wonder about).
Maybe you can ask yourself "What is the name of my page or window that interracts with this service ?" Is there only one or more ? If more, what do they have in common ?
This could help you figure out a good name for your service, and consequently different methods to acquire what each needs.
Tell me more. I will be please to help.
I am making an application in c#.I am using .Net Remoting for calling the method of windows application in web application.For communication between windows and web application i made one remoting object in which i declare one method.In windows application i have collection of one class and that class is declared in remote object.
Now my problem is that whenever i am calling the interface method,the collection value becomes zero.Before calling that method it contains some data.
Also whenever i am inserting hard coded value then its working but whenever i am inserting runtime value,its giving problem.I am using threading to insert the data into the collection.
Remote object has two components as StreamDataInfo.cs and IRemoteStreamData.cs as.These two are different classes in one class library.
namespace StreamDataService
{
public interface IRemoteStreamData
{
List<string> GetPatientHistory(string BedID);
}
}
namespace StreamDataService
{
[Serializable] public class StreamDataInfo:MarshalByRefObject
{
public string m_PortNumber { get; set; }
public string m_BedID { get; set; }
public List<string> m_StreamData { get; set; }
}
}
And in server application i wrote interface method as
public List<string> GetPatientHistory(string PortNumber)
{
StreamDataInfo objStreamDataInfo = new StreamDataInfo();
lock (this)
{
objStreamDataInfo = (from temp in listStreamDataInfo
where temp.m_PortNumber.Equals(PortNumber.ToString())
select temp).SingleOrDefault();
}
return objStreamDataInfo.m_StreamData;
}
Please help me.Thanks in advance.
Generic collections are not supported in remoting. You can either use arrays or try your own implementation (a VB sample is here).
I'm prototyping a tool that will import files via a SOAP api to an web based application and have modelled what I'm trying to import via C# interfaces so I can wrap the web app's model data in something I can deal with.
public interface IBankAccount
{
string AccountNumber { get; set; }
ICurrency Currency { get; set; }
IEntity Entity { get; set; }
BankAccountType Type { get; set; }
}
internal class BankAccount
{
private readonly SomeExternalImplementation bankAccount;
BankAccount(SomeExternalImplementation bankAccount)
{
this.bankAccount = bankAccount;
}
// Property implementations
}
I then have a repository that returns collections of IBankAccount or whatever and a factory class to create BankAccounts for me should I need them.
My question is, it this approach going to cause me a lot of pain down the line and would it be better to create POCOs? I want to put all of this in a separate assembly and have a complete separation of data access and business logic, simply because I'm dealing with a moving target here regarding where the data will be stored online.
This is exactly the approach I use and I've never had any problems with it. In my design, anything that comes out of the data access layer is abstracted as an interface (I refer to them as data transport contracts). In my domain model I then have static methods to create business entities from those data transport objects..
interface IFooData
{
int FooId { get; set; }
}
public class FooEntity
{
static public FooEntity FromDataTransport(IFooData data)
{
return new FooEntity(data.FooId, ...);
}
}
It comes in quite handy where your domain model entities gather their data from multiple data contracts:
public class CompositeEntity
{
static public CompositeEntity FromDataTransport(IFooData fooData, IBarData barData)
{
...
}
}
In contrast to your design, I don't provide factories to create concrete implementations of the data transport contracts, but rather provide delegates to write the values and let the repository worry about creating the concrete objects
public class FooDataRepository
{
public IFooData Insert(Action<IFooData> insertSequence)
{
var record = new ConcreteFoo();
insertSequence.Invoke(record as IFooData);
this.DataContext.Foos.InsertOnSubmit(record); // Assuming LinqSql in this case..
return record as IFooData;
}
}
usage:
IFooData newFoo = FooRepository.Insert(f =>
{
f.Name = "New Foo";
});
Although a factory implementation is an equally elegant solution in my opinion. To answer your question, In my experience of a very similar approach I've never come up against any major problems, and I think you're on the right track here :)
I have a Silverlight solution that references a third-party web service. This web service generates XML, which is then processed into objects for use in Silverlight binding. At one point we the processing of XML to objects was done client-side, but we ran into performance issues and decided to move this processing to the proxies in the hosting web project to improve performance (which it did). This is obviously a gross over-simplification, but should work. My basic project structure looks like this.
Solution
Solution.Web - Holds the web page
that hosts Silverlight as well as
proxies that access web services and
processes as required and obviously
the references to those web
services).
Solution.Infrastructure - Holds
references to the proxy web services
in the .Web project, all genned code
from serialized objects from those
proxies and code around those objects
that need to be client-side.
Solution.Book - The particular
project that uses the objects in
question after processed down into
Infrastructure.
I've defined the following Interface and Class in the Web project. They represent the type of objects that the XML from the original third-party gets transformed into and since this is the only project in the Silverlight app that is actually server-side, that was the place to define and use them.
//Doesn't get much simpler than this.
public interface INavigable
{
string Description { get; set; }
}
//Very simple class too
public class IndexEntry : INavigable
{
public List<IndexCM> CMItems { get; set; }
public string CPTCode { get; set; }
public string DefinitionOfAbbreviations { get; set; }
public string Description { get; set; }
public string EtiologyCode { get; set; }
public bool HighScore { get; set; }
public IndexToTabularCommandArguments IndexToTabularCommandArgument { get; set; }
public bool IsExpanded { get; set; }
public string ManifestationCode { get; set; }
public string MorphologyCode { get; set; }
public List<TextItem> NonEssentialModifiersAndQualifyingText { get; set; }
public string OtherItalics { get; set; }
public IndexEntry Parent { get; set; }
public int Score { get; set; }
public string SeeAlsoReference { get; set; }
public string SeeReference { get; set; }
public List<IndexEntry> SubEntries { get; set; }
public int Words { get; set; }
}
Again; both of these items are defined in the Web project. Notice that IndexEntry implments INavigable. When the code for IndexEntry is auto-genned in the Infrastructure project, the definition of the class does not include the implmentation of INavigable. After discovering this, I thought "no problem, I'll create another partial class file reiterating the implmentation". Unfortunately (I'm guessing because it isn't being serialized), that interface isn't recognized in the Infrastructure project, so I can't simply do that. Here's where it gets really weird. The BOOK project CAN see the INavigable interface. In fact I use it in Book, though Book has no reference to the Web Service in the Web project where the thing is define, though Infrastructure does. Just as a test, I linked to the INavigable source file from indside the Infrastructure project. That allowed me to reference it in that project and compile, but causes havoc in the Book project, because now there's a conflick between the one define in Infrastructure and the one defined in the Web project's web service. This is behavior I would expect.
So, to try and sum up a bit. Web project has a web service that process data from a third-party service and has a class and interface defined in it. The class implements the interface. The Infrastructure project references the web service in the Web Project and the Book project references the Infrastructure project. The implmentation of the interface in the class does NOT serialize down, so the auto-genned code in INfrastructure does not show this relationship, breaking code further down-stream. The Book project, whihc is further down-stream CAN see the interface as defined in the Web Project, even though its only reference is through the Infrastructure project; whihc CAN'T see it.
Am I simple missing something easy here? Can I apply an attribute to either the Interface definition or to the its implmentation in the class to ensure its visibility downstream? Anything else I can do here?
I know this is a bit convoluted and anyone still with me here, thanks for your patience and any advice you might have.
Cheers,
Steve