Eager Loading Faulting WCF with Entity Framework 6 - c#

I have a WCF service project that is faulting when I am trying to eager load entities. (.Include).
My setup is like this:
WCF Service Library Project
Class Library Project -- Edmx is housed there
Class Library Project -- View Models housed there
WPF Project
I have spent some time trying to fix this serialization issue when I am eager loading entities.
Here is where I am now. The below works:
[OperationContract]
[FaultContract(typeof(HandleException))]
[ApplyProxyDataContractResolver]
List<Item> GetItems();
using (var dbContext = new MyEntities())
{
dbContext.Configuration.LazyLoadingEnabled = false;
return dbContext.Items.ToList();
}
And displays this:
But this faults and gives the generic error message
Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.
This is what is throwing the exception
return dbContext.Items.Include(x => x.Category).ToList();
I have tried changing the return type to Item and then something like this
return dbContext.Items.Include(x => x.Category).FirstOrDefault(t => t.Category.CategoryId == t.CategoryId);
And I have added [CyclicReferencesAware(true)] but the test client is still bombing out.
Categories are a self referencing hierarchy -- I think that is why it can't handle it.
How can I resolve this?
Thanks.

WcfTestClient.exe can't handle cyclic references - have you tried testing with your own custom code?

Related

WCF project trying to recreate database when it exists already

So I am attempting to utilize EF and my existing database in a WCF project in order to add some entities to the database.
Setup:
So I have several layers to my solution.
Core (class library)
Data (class library)
Services (class library)
WCFServices(WCF application)
WebUI (MVC project)
Entity framework 6.2.0 is installed in my Data, WCFServices, and WebUI project. (picture below).
So my database models are stored in the core project and my migrations for the database are stored in the data project. My web UI project has no issues accessing the database and using it. I have the exact same connection strings stored in both the MVC project and the WCF project.
MVC web.config connection string
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-SQDCDashboard.WebUI-20190610100239.mdf;user id = exampleUser; password = ExamplePassword;Integrated Security=False" providerName="System.Data.SqlClient" />
The WCF project has the following connection string.
WCF web.config connection string
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-SQDCDashboard.WebUI-20190610100239.mdf;user id = exampleUser; password = ExamplePassword;Integrated Security=False" providerName="System.Data.SqlClient" />
As you can see they both match exactly.
WCF service
public class OrderService : IOrderService
{
public string InsertOrder(OrderDTO order)
{
try
{
using (var context = new DataContext())
{
var productionLine = context.ProductionLines
.Where(x => x.ComputerName == order.ComputerName)
.FirstOrDefault();
if (productionLine == null)
throw new Exception("Production line could not be determined from computer name");
context.Orders.Add(new Core.Models.Order
{
MaterialNumber = order.MaterialNumber,
SerialNumber = order.SerialNumber,
ProductionNumber = order.ProductionNumber,
SalesNumber = order.SalesNumber,
OrderComplete = false,
ProductionLineId = productionLine.Id
});
context.SaveChanges();
return "Success";
}
}
catch (Exception ex)
{
return ex.Message;
}
}
}
The Error
So here is where the issue comes in. When I run the WCF test client to test my service, it throws the following error:
Cannot create file 'C:\Users\eric_obermuller\Source\Repos\SQDC Dashboard\SQDCDashboard\SQDCDashboard.WCFServices\App_Data\aspnet-SQDCDashboard.WebUI-20190610100239.mdf' because it already exists. Change the file path or the file name, and retry the operation.
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
This really confuses me because the database already exists. Why is it trying to create a new one? I am a bit of a beginner when it comes to structuring multiple projects in a single solution. So it could possibly be I just don't understand how EF is interacting between the projects?
I did notice that both my WCF project and my MVC project have their own database files in their respective App_Data folders. I have to say I am not sure how EF uses these files in conjunction with the actual local db, it has always sort of confused me so I may be missing something here (see below).
What I have tried
Originally I was using windows authentication but tried switching to SQL Server authentication (which is what I will end up using later).
I tried deleting the migrations folder in my project and dropped the database migrations table. I re-enabled migrations, added an empty migration, and updated the database.
I triple checked that the SQL Server account I am referencing has read/write permissions to the database.
Final Remarks
Again, I have 0 issues using the database within my actual MVC web UI project. My MVC project does use ninject to inject dependencies from my Service project into the controllers, it also injects the dbContext (stored in my data project) into some generic repositories (also stored in my data project), which are used in my Services class library project.
My WCF project does NOT use ninject in any manner, I am directly referencing the dbcontext, as this service is a very simple one and has no need for all that. So I could also see this being the possible issue?
Which DatabaseInitializer you have setup for DB migrations? if you are using 'DropCreateDatabaseAlways' initializer and have same database for two application running in parallel then that might be causing the problem.
While your MVC app is running fine, but WCF will fail while booting up the DBContext as it will try to drop and recreate the Database.
Change your database initializers to the one that would fit this scenario. "DropAndRecreateAlways/ModelChange" are not best candidates.

WCF Data Service 5.6 quick start

I have been trying to get a WCF Data Service server working for a few days now.
I finally backed off today and just tried to do exactly what the quick-start shows.. nothing else.. and in completely fresh project. Surely that would work.
But it didn't.. it failed the same way as my other tests.
I am just following along with this example. Using Visual Studio 2013 for Web express and the hosting is using IIS Express.
I have installed the WCF Tools version 5.6 such that Visual Studio has the WFC Data Service 5.6 template.
The gist of it is
create an ASP.Net Application Select MVC type, adding no folders for anything other than MVC and no unit tests, individual account authenticaion.
Add an ADO.Net Entity Data Model for the NorthWind database, called NorthwindEntities in web.config, importing all tables.
Add WCF Data Service 5.6 item, call it NorthWind.svc.
Change the NorthWind.svc.cs backing code to the following.
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
namespace StackOverflowApp
{
public class NorthWindService : DataService<NorthwindEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.UseVerboseErrors = true;
config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead | EntitySetRights.WriteMerge | EntitySetRights.WriteReplace );
config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead| EntitySetRights.AllWrite);
config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
}
Now it is ready to build and run.. it should work.. yes?
I run it, and navigate to the service.. I am greeted with the following complaint.
<div id="content">
<p class="heading1">Request Error</p>
<p>The server encountered an error processing the request. See server logs for more details.</p>
</div>
How am I to debug that?
This is not the typical response when navigating to a page which generates an error in the application or to a page that does not exist. I get the feeling that the data.service system is generating this response.. that it actually started to process the request.. but failed for some obtuse reason.
I followed the instructions to a tee I thought, but apparently I missed something.
I've been through the process step by step several times now to try to find what I might have skipped to no avail.
Update:
Aha.. under another similar question, they recommended adding verbose messages using config.UserVerboseErrors = true. This didn't make any difference to me.. but the alternative method of using attributes sure did! Decorating the class with [ServiceBehavior(IncludeExceptionDetailInFaults = true)], now yields this more descriptive error.
The server encountered an error processing the request. The exception
message is 'Expression of type
'System.Data.Entity.Core.Objects.ObjectContext' cannot be used for
return type 'System.Data.Objects.ObjectContext''. See server logs for
more details. The exception stack trace is: blahblah
It sounds like you're using Entity Framework 6 which hasn't been out for all that long. You need to perform some additional steps to get WCF Data Services 5.6 and EF 6 to behave together nicely.
You need to add the additional WCF Data Services Entity Framework Provider Nuget package and then instead of inheriting your service from DataService<T>, you inherit from EntityFrameworkDataService<T>.
Full steps are on the data services blog here: http://blogs.msdn.com/b/astoriateam/archive/2013/10/02/using-wcf-data-services-5-6-0-with-entity-framework-6.aspx
Yes Thanks. Your answer is correct Chris. I was able to find the problem at last after I enabled the decorated version of verbose messaging, and got that extra detail regarding linking to objects being the problem.
So I found the problem and fixed it, or at least I can make it work using the quick-start guide now. Working with my own database is a little squirley still.. returns an empty set when I know I have items in the database.. but at least I now have working exhibit-A to compare against to find the issue. (Aha! found the problem there also, I had forgotten to add the entitie connection to web.config for my non-northwind database -- so its all workin' now!)
Anyway, the first decent clue was following the error message (that wasn't shown until after I enabled verbose messaging with the class attribute), found this note about the problem actually being with WCF's interface with EntityFramework 6. (had I not upgraded to version 6 I likely would not have had the problem)
https://entityframework.codeplex.com/workitem/896
Then, I searched for issues with WCF 5.6 and EntityFramework6. and whalla.. there is an alpha version of WCF which addresses the issue.
Note that if you follow the instructions here verbatim, there is still a problem (or was for me). Get alpha2 instead of alpha1 as it fixes a linking error. i.e.
Install-Package Microsoft.OData.EntityFrameworkProvider -Version 1.0.0-alpha2 -Pre
http://blogs.msdn.com/b/astoriateam/archive/2013/10/02/using-wcf-data-services-5-6-0-with-entity-framework-6.aspx
To install alpha2 today 6/7/2014 "Install-Package Microsoft.OData.EntityFrameworkProvider -Pre". Also the Microsoft.Data.Services version must be 5.6.0.0.

WCF, POCO and inheritance: data contract issue

I have a WCF server application using Entity Framework 5.0 and POCO entities. The server serializes POCOs directly to the client application over WCF (I managed to do this by following instructions in the following blog post: http://www.sanderstechnology.com/?p=10142). This has been working pretty well until I encountered a new problem today.
I have a simple situation in my data model shown in the following image: http://roponenp.kapsi.fi/images/datamodel.png
In my server I have a method that can be used for getting blocks:
[OperationContract]
[ApplyDataContractResolver]
[CyclicReferencesAware(true)]
List<Block> GetBlocks();
I need to include projects linked to the blocks to my response, so I do the following:
public List<Block> GetBlocks()
{
using (ModelContainer db = new ModelContainer())
{
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
return db.Block.Include(it => it.Project).ToList();
}
}
In my database I have instances of types ProjectA and ProjectB (that are inherited from Project). So the LINQ query above includes actually types of ProjectA and ProjectB to my response. Those types get serialized and are sent to the client. When this happens, I get the following error in the client side (there comes no errors in the server application):
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
The problem seems to be that in my data contract type Block is linked to type Project. However, my response returns data containing types ProjectA and ProjectB linked to Blocks.
I have no idea how I can solve this problem. I think it can be solved by implementing a custom DataContractResolver, but I haven't found any working examples how this could be done.
Any ideas?
You will need a KnownType Attribute if your object contains other types than obvious (for example interface implementations or derived classes).
Check the example in the MSDN, it's pretty good.
[ServiceContract]
[KnownType(typeof(ProjectA))]
[KnownType(typeof(ProjectB))]
class SomeService
{
[OperationContract]
[ApplyDataContractResolver]
[CyclicReferencesAware(true)]
List<Block> GetBlocks();

ComponentResolutionException after upgrading to Castle 3.0

I've just upgraded a solution from .NET 3.5 to .NET 4
In the same time, I've upgraded all external libraries to the latest version, so Castle is now upgraded from 2.5.2 to v3.0
I've some code that register db access that throw now an Exception when I try to resolve:
[Castle.MicroKernel.ComponentResolutionException] {"Could not obtain
scope for component DF.MailFlowAdapter. This is most likely either a
bug in custom IScopeAccessor or you're trying to access scoped
component outside of the scope (like a per-web-request component
outside of web request
etc)"} Castle.MicroKernel.ComponentResolutionException
The component is registered this way:
Container
.AddFacility<WcfFacility>()
.AddFacility<DataAccessAdapterFacility>()
.Register(Component
.For<SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter>()
.ImplementedBy<MailFlowAdapter>()
.LifeStyle.PerWcfOperation())
The problem comes from the PerWcfOperation LifeStyle, but I don't know why: The project is a WCF project and the component is resolved when calling a WCF method.
This registration is working fine in the branch that use Castle 2.5.
The exception is thrown when Validating the wcf login/pwd (in a IAuthorizationPolicy that use a UserNamePasswordValidator), because I resolve an IDataAccessAdapter (to check login/pwd in the db).
Other piece of information:
The DataAccessAdapterFacility is an old code that register a component activator, I had to slightly change de code because model.Service changed to model.Services:
void Kernel_ComponentModelCreated(ComponentModel model)
{
foreach (var service in model.Services)
{
if (service == typeof(SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter))
{
model.CustomComponentActivator = typeof(DataAccessAdapterActivator);
}
}
}
And the DataAccessAdapterActivator has in charge to create the object using a connection string in the config file:
protected override object InternalCreate(CreationContext context)
{
var connectionString = string.Empty;
if (ConfigurationManager.ConnectionStrings["Main"] != null)
connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString;
return new MailFlowAdapter(connectionString);
}
I think the code with DataAccessAdapterFacility/DataAccessAdapterActivator could be simplify using Factory but it's not the question here :)
So does someone have an idea on why I can't use PerWcfOperation lifestyle ?
I don't believe an OperationContext.Current is available at the point where a custom UserNamePasswordValidator is called. Is it possible to use another lifestyle for that component?
Ok Let's resume my discussion with Craig Neuwirt on the castle mailing list:
The behaviour has changed, in v2.5 is was falling back on a
transient lifestyle. But as it was not consistent (No info on when
the component was PerWcfOperation and when it was Transient) this has
been removed.
It's possible to do the same using a custom lifestyle scope accessor
I'll not post my code here as it's trivial once you've read how the Hybrid lifestyle are done in the castlecontrib project

XML namespace problem in Visual Studio generated service reference

I'm connecting to a web service hosted by a third-party provider. I've added a service reference in my project to the web service, VS has generated all the references and classes needed.
I'm connecting with this piece of code (client name and methods anonymized):
using (var client = new Client())
{
try
{
client.Open();
var response = client.Method(...);
return response.Status;
}
catch (SoapException ex)
{
throw CreateServiceException(ex);
}
finally
{
client.Close();
}
}
When reaching the client.Open(), I get an exception with this message:
The top XML element '_return' from
namespace '' references distinct types
System.Boolean and
Service.Status.
Use XML attributes to specify another
XML name or namespace for the element
or types.
In reference.cs, I can see that the "_return" variable is decorated with
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
Is there a problem with the wsdl, the generated service reference or in my code?
Update: Generating the service as an old school Web Service solves the problem. I've marked Sixto's answer as accepted for now, but I'm still curious what could've caused the problem and if any parameters to the service generator could solve the original problem.
If you were able to create a service reference then the WSDL is valid. The exception message is saying you have namespace/type ambiguity problem with _return. The generated code is probably using it in some context as a boolean and in another context as a Service.Status type.
I don’t call the ClientBase.Open method before invoking a service method because I’ve never seen the need for it. I do always call the Close & Abort methods as appropriate. The Open method basically just changes the state of the client to no longer be configurable. I’m not sure how that would trigger code in the generated class since it is an inherited method. I’d try just removing that line and see if you get the same exception. Otherwise, if you haven’t already done so, search the generated code for all the places _return is used and see if you can manually sort-out the appropriate type. You may need different names for each context.
Another way to troubleshoot the WSDL is to create a Web Reference (assuming it’s an HTTP based service) and see if the generate code works as expected. If it does work, go with the ASMX client unless you have a need for WCF proxy capabilities.

Categories

Resources