I have a solution with the following structure:
Domain (.NET 4.6.1)
DAL (.NET 4.6.1)
BLL (.NET Core 2.0)
API (.NET Core 2.0)
I have a requirement to submit data to an external WCF service. I personally do not have a lot of experience with WCF as I have been working with REST APIs. So to try out consuming a WCF service, I have set up a .NET core console application in and added a connected service reference to it. This resulted in a generated Reference.cs with the following classes:
IWebService
IWebServiceChannel
SendResponse
GetResponse
WebServiceClient (implementing IWebService)
I was thinking about creating a SubmissionService class in the BLL layer to submit data to the WCF service, so I moved IWebService from the console app to the BLL layer to inject into the class and perform unit testing. The attributes defined on the IWebService requires a reference to System.ServiceModel which comes with a lot of baggage and it does not make sense to reference it in my BLL layer.
I am not sure where to put the WCF client in my project structure. I have been investigating this issue and the only viable solution I can think of is to create a class library project purely for the WCF client and reference that in my BLL layer to have access to IWebService and mock it for testing. Has anyone been in the same situation? Any help is greatly appreciated.
You are missing a 'layer', namely the Composition Root. (for a more detailed explanation, see section 4.1 of this book).
You can define your own application-specific abstraction that allows the BLL to talk with the WCF service (through that abstraction). That abstraction can be located in the BLL.
Within your Composition Root, you can create an adapter on top of that application-specific abstraction that calls into the WCF service, using the WCF client, which can be generated inside the Composition Root as well.
Related
Our asp.net core solution has is separated into the following layers:
Web UI Projects (3 different web applications)
BLL
Entities (Models and View Models)
DAL (DBContext, Repositories)
All Web UIs will leverage services from the BLL which will in turn reference the DAL to interface with the data. Typically, a service for the DBContext is configured in the startup class.
Is there a way to truly separate this such that the web ui projects do not need to reference the DAL (DBContext) while still using DI? I get it that for dependency injection to occur, the DBContext needs to be configured as a scoped service in startup of the web ui, but logically it does not make any sense to me that the UI needs to reference or have anything to do with the DAL.
I recommend using these layers:
Web UI (models with validation attributes- data format, required, etc)
Service
Contract DLL (interface + entities)
Implementation (controller actions)
Data Access
Share the contract DLL between the service and the web UI. Inside the service use whatever DAL / ORM you prefer. Personally, I prefer Dapper.
Then, generate C# proxies to your JSON service using Refit. Inject Refit proxies into your web controllers via the website's Startup class. Put most of the business logic in the service controllers and call them from the website controllers. Keep logic in the website controllers to a minimum.
With this design, the web UI has no knowledge of the data access layer. You can switch it from Dapper to Entity Framework if you wish. Refit + a JSON service gives you the benefits of type-safe C# code on both ends (web and service) and the flexibility to write raw HTTP posts when required (say, from AJAX code running in the web browser).
And you can write C# or PowerShell utilities that leverage the service. In other words, the website need not be the only consumer of the service.
I have an ASP.NET project that exposes multiple WCF Services.
Most these services make use of common custom classes in the APP_Code folder used throughout the project.
Consuming these WCF services is a console app I have written.
My question is :-
In the console app I obviously instantiate each of the WCF services I'm using - but some of these services utilise the common classes as parameters to some of the methods.
However on the client side (console app) - those classes are exposed exclusively as part of that WCF Service's namespace and not interchangeable)
Example of syntax error is something like :-
cannot convert from 'ManagementAgent.Computer_ServiceReference.ComputerIdentity' to 'ManagementAgent.WorkloadAnalysis_ServiceReference.ComputerIdentity'.
The class "ComputerIdentity" is a commonly shared class in the App_Code folder.
How do I get this class interchangeable as a parameter across multiple WCF Services?
Your shared classes need to come from the same assembly, not just shared code. Put the classes you want to share into their own class library and reference that in all projects.
I'm writing simple CRUD-like MVC app at the moment, trying to learn proper N-tier architecture, and so far i had MVC which gets objects through WCF which call my Data Access layer to get those objects from Database.
However I just realized most likely huge mistake I'm making, I left all generated authentication stuff where it was - in MVC project except ApplicationUser and ApplicationDbContext which i moved to Business layer and Data Access layer accordingly and referenced them which I think defeats purpose of Service. How do I move properly authentication to service in this case? Perhaps there is a sample N-Tier project which has authentication moved to service and all?
So far my references are like this:
MVC client knows about Service(as service reference), Business layer
Service knows about Data Access, Business Layer
Data Access knows about Business layer.
this might help you! this explains asp.net identity with Design Patterns
http://timschreiber.com/2015/01/14/persistence-ignorant-asp-net-identity-with-patterns-part-1/
We have the following structure on our project in order to get data.
Acces to Database Using Entity Framework
ProjectName.DAL
Services that call Entity Framework.(UoW)
ProjectName.Service
Our Actions inside Controllers call Services and return data needed.
ProjectName.Web
The Question:
Our services take info directly with Entity Framework, What are the advantages and disadvantages about creating WebServices in order to replace the connection with EF? "In that case only WebServices will have access to Entity Framework,"
ProjectName.DAL
ProjectName.WebServices
ProjectName.Service
ProjectName.Web
The main advantage is that you would have a more decoupled design.
By exposing your DAL through web services you "disconnect" it from your frontend. For example, a mobile app, a web app and a WPF desktop app could all access your DAL through the same web services. So you can reuse your DAL accross different apps which can save you a lot of development time. Have a look at ServiceStack and advantages of its web services.
Disadvantages? Having to do some additional development work and testing. If your app is a simple and will not be used in different environments it may be overkill to use web services.
Disadvantages:
Web services tend to consume more resources from your server than just a plain CLR (aka dll) layer in your project.
whatever web service you plan to use (legacy web services, service stack, wcf, Web API, etc) you'll find that all of them have to use a process to serialize the data and it could be the case that you'll need to do the inverse process in your front end application.
you have to design your ws very carefully because you have to think how you're going to expose those services and the level of encapsulation/abstraction you will have to put in place, a bad design in a web service layer definetely will be a headache for you during development and production.
Security: In most cases you will have to validate every input in those web services as well
Advantages
well that's very relative to call an advantage, it depends more on what are your app requirements, some questions you need to answer are like the following:
Do I need to share data with other apps (mobile, desktop, other web
apps)?
Do I need to expose some functionalities to other business (third
parties)?
Recomendation
If you plan to do a CRUD application I'll recomend to go with REST definetely is the best option due to it's architecture (POST,DELETE,GET,ETC).
if you don't need you a web service right now, you can try to develop your service layer kind of like a service implementation in service stack but try to remain as POCO as possible and if for some reason you'll need a web service you can try to refector the service layer intead to have another level of indirection in the middle.
just my two cents...
The project we are working on is a classic 3 tiered architecture. tier 1 being the database server, tier 2 the application services and tier 3 the presentation tier (a web site).
In the application services tier I have a project that includes an entity framework model and a WCF data services based service that exposes the entities within the model e.g.:
public class DataService : DataService< PortalEntities >
This is a fully fledged OData service that can be queried through the URI e.g.: /dataservice.svc/mytable?$filter=contains(fieldname,’string’). This is great for the guys developing anything using jQuery as all they have to do is define the query. The problem is that this service is a mid-tier so it cannot be seen by the outside world.
The solution that I am trying is to expose another WCF data service on the web site that exposes the entities created by the service reference. If I add a service reference to the mid-tier service it gives me a data context that data context is being used in the new WCF Data service:
public class DataService : DataService< PortalEntities >
I do have to overwrite the CreateDataSource:
protected override PortalEntities CreateDataSource()
{
return new PortalEntities(GetMianModelServiceUri());
}
The new service does act like a proxy and does return the entities exposed (the query .../Services/OData/DataService.svc/tbl_Country works fine).
But when a query is passed to the service e.g.: .../OData/DataService.svc/tbl_Country?$select=Name it throws a not implemented exception.
Any ideas on how to extend the web site service so that it supports the same queries as the mid-tier service?
If you don't need to change the shape or functionality of the data server, you should be able to simply forward the requests and responses, just like a transparent HTTP proxy. The only difference you might need to do is to tweak the service URL. Since the proxy service will have a different base URI than the real service, the payload would contain the real service URIs (in the links and such), which would not work. You can workaround this by using a custom host for your real service and lie to it about its URI. This is done through IDataServiceHost2 interface, you return the "new" URI from the AbsoluteRquestUri and AbsoluteServiceUri properties. Nice sample of an implementation of the interface (although for a different purpose) is here: Link.
If you need to change the shape or functionality, then you really need a true layering.
Layering one WCF Data Service over another is currently rather hard. The LINQ expression trees generated by the "Server" are not always understood by the "Client" LINQ provider. That's what you're running into.
There's a prototype (more like an experiment) of making this work to some extent by rewriting the expression trees. It's part of the OData Provider Toolkit which you can download here http://www.odata.org/developers/odata-sdk#/media/7579/odataprovidertoolkit.zip. (It's in the Experimental folder, AstoriaOverAstoria project).
But please be aware that this is really just an experiment to show what kind of issues are there to be solved and so on. I definitely recommend to NOT use it in any kind of production environment.
I have found it possible to expose a service on the Web Tier that references a service (not data directly) on the App Tier. This only works for queries at the moment. I am not sure what is needed to get it working for updates, deletes etc. Any Ideas anyone? Anyway, here are some instructions and code snippets:
First you create a WCF Data Service on the App Tier bound to your edmx model.
Then create WCF Data Service on the Web Tier not bound to an edmx model (custom).
Create a Service Reference in the Web Tier Service to the App tier service.
Pass the Entities type to the DataService generic declaration (should be angle brackets for VB but I couldn't get them to show:
Public MyWebTierService
Inherits DataService[MyServiceReference.MyAppTierEntities]
Add an override for CreateDataSource() that creates your reference to the App Tier:
Protected Overrides Function CreateDataSource() As MyServiceReference.MyAppTierEntities
Dim ctx = New MyServiceReference.MyAppTierEntities(New Uri("http://yourappservicelocation/AppService.svc/"))
Return ctx
End Function
All you do now is create a reference to the service or bind it to your client app that
supports OData. JSONP support can be added if required.
So, this works fine for Queries but not for updates, probably because the Types are not the same (they may look the same, but are in difference assemblies after all). So, tracking is lost between the Web and App Tiers.
It may be that we have to implement IUpdatable on the Web Tier to solve this. Not sure yet so any input would be useful.
Hope this helps