RavenDB Embedded on Azure Websites - Access Denied - ravendb

I get an Access denied message when I try to deploy my MVC4 site with an Embedded instance of RavenDB to the new Azure Websites preview feature. The site works fine locally.
Here is how I configure Raven:
//Initialize the RavenDB Data Store
Raven.Database.Server.NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(8887);
var documentStore = new EmbeddableDocumentStore()
{
DataDirectory = "~\\App_Data",
UseEmbeddedHttpServer = true,
Configuration = { Port = 8887 }
};
documentStore.Initialize();
And here is the stack trace when I browse to the site:
Access is denied
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Net.NetworkInformation.NetworkInformationException: Access is denied
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[NetworkInformationException (0x5): Access is denied]
System.Net.NetworkInformation.SystemIPGlobalProperties.GetAllTcpConnections() +1570717
System.Net.NetworkInformation.SystemIPGlobalProperties.GetActiveTcpListeners() +74
Raven.Database.Util.PortUtil.FindPort() in c:\Builds\RavenDB-Unstable-v1.2\Raven.Database\Util\PortUtil.cs:110
Raven.Database.Util.PortUtil.GetPort(String portStr) in c:\Builds\RavenDB-Unstable-v1.2\Raven.Database\Util\PortUtil.cs:44
Raven.Database.Config.InMemoryRavenConfiguration.Initialize() in c:\Builds\RavenDB-Unstable-v1.2\Raven.Database\Config\InMemoryRavenConfiguration.cs:170
Raven.Database.Config.RavenConfiguration.LoadConfigurationAndInitialize(IEnumerable`1 values) in c:\Builds\RavenDB-Unstable-v1.2\Raven.Database\Config\RavenConfiguration.cs:28
Raven.Database.Config.RavenConfiguration..ctor() in c:\Builds\RavenDB-Unstable-v1.2\Raven.Database\Config\RavenConfiguration.cs:17
Raven.Client.Embedded.EmbeddableDocumentStore.get_Configuration() in c:\Builds\RavenDB-Unstable-v1.2\Raven.Client.Embedded\EmbeddableDocumentStore.cs:63
Raven.Client.Embedded.EmbeddableDocumentStore.set_DataDirectory(String value) in c:\Builds\RavenDB-Unstable-v1.2\Raven.Client.Embedded\EmbeddableDocumentStore.cs:90
Solarity.DesignSearch.Website.Bootstrapper.BuildUnityContainer() in c:\a\src\Solarity.DesignSearch\Solarity.DesignSearch.Website\Bootstrapper.cs:35
Solarity.DesignSearch.Website.Bootstrapper.Initialise() in c:\a\src\Solarity.DesignSearch\Solarity.DesignSearch.Website\Bootstrapper.cs:20
Solarity.DesignSearch.Website.MvcApplication.Application_Start() in c:\a\src\Solarity.DesignSearch\Solarity.DesignSearch.Website\Global.asax.cs:23
[HttpException (0x80004005): Access is denied]
System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +9859725
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +118
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +336
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +296
[HttpException (0x80004005): Access is denied]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9873912
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +101
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +254

I managed to get it to work, although it is not ideal. You may notice in my original post that I am setting the UseEmbeddedHttpServer = true. This is so that I can browse to http:[MyUrl]:8081 and get the RavendDB Management Studio so that I can browse my data. For some reason, RavenDB wants to do the same kind of port check when this property is set as it does when you set the Port setting to automatic (Port=*).
I believe that RavenDB may need a fix so that it honors the Port setting when UseEmbeddedHttpServer is True and also let you set the Configuration property of the EmbeddedDocumentStore upon creation.
But in the meantime, you can truly get your MVC4 site to work with an EmbeddedDocumentStore on Azure Websites simply by specifying a port. Also, you do indeed have to use the AppSettings configuration rather than setting the Configuration property of the EmbeddedDocumentStore upon creation (like I tried to do above). This post (stackoverflow.com/questions/11529159/) shows how to do it.
Unfortunately, I still haven't found a way to run the EmbeddedHttpServer so I can use the Raven Management Studio. If I figure out how, I will post a solution here.

Hi this was answered on RavenDb on Azure Websites - Access Denied
Basically you need to configure the port in Web.config

Related

Sign Up/In not working in ASP. NET Core application: Azure B2C

We configured user flow with Google as identity provider. Followed the Azure-Sample repository on GitHub in building one ASP.NET Core webapp with .NET6.
appsettings.json:-
"AzureAdB2C": {
"Instance": "https://b2ctenant.b2clogin.com",
"ClientId": "3ae27e38-90a3-43c7-9bac-8d3bf33227f9",
"Domain": "b2ctenant.b2clogin.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi",
"SignUpSignInPolicyId": "b2c_1_susi",
"ResetPasswordPolicyId": "b2c_1_reset",
"EditProfilePolicyId": "b2c_1_edit_profile" // Optional profile editing policy
//"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc
https://localhost:44316
Getting exception when users select Sign Up/In option
IOException: IDX20807: Unable to retrieve document from: '[PII of type 'System.String' is hidden. For more details, see
https://aka.ms/IdentityModel/PII.]'. HttpResponseMessage: '[PII of
type 'System.Net.Http.HttpResponseMessage' is hidden. For more
details, see https://aka.ms/IdentityModel/PII.]',
HttpResponseMessage.Content: '[PII of type 'System.String' is hidden.
For more details, see https://aka.ms/IdentityModel/PII.]'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string
address, CancellationToken cancel)
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(string
address, IDocumentRetriever retriever, CancellationToken cancel)
Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken
cancel)
nvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII of type 'System.String' is hidden. For more
details, see https://aka.ms/IdentityModel/PII.]'.
Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken
cancel)
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsyncInternal(AuthenticationProperties
properties)
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsync(AuthenticationProperties
properties)
Microsoft.AspNetCore.Authentication.AuthenticationHandler.ChallengeAsync(AuthenticationProperties
properties)
Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext
context, string scheme, AuthenticationProperties properties)
Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext
context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|30_0<TFilter,
TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next,
Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed
context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter,
TFilterAsync>(ref State next, ref Scope scope, ref object state, ref
bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|28_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, object state, bool
isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, object state, bool
isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed
context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State
next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, object state, bool
isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker
invoker)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker
invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint
endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext
context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext
context)
I tried to reproduce the same in my environment and got below results:
I registered one application and granted API permissions like below:
I cloned the same GitHub sample and updated appsettings.json file same as you like below:
I ran the above sample and got below screen:
When I clicked on Sign Up/In button, I got same error as you like below:
Note that, you are giving wrong value to your Domain parameter in your appsettings.json file. You need to change value of Domain parameter that can be found here:
To resolve the error, I changed value of Domain parameter in my
appsettings.json file like below:
When I clicked on Sign Up/In button now by running the sample, I got the login screen with Google successfully like below:
Reference: Configure authentication using Azure Active Directory B2C | Microsoft

ReflectionTypeLoadException in ASP.NET Core MVC application

I'm running into a problem running an ASP.NET Core 1.0 application targeting .NET Framework 4.6. The problem didn't occur until we tried to run the application on a server running Windows Server 2016. The app is hosted in IIS and I have the .NET Core 1.0 Windows Hosting Bundle installed on the server.
Upon loading the site a 500 error is returned and this is written to the Logs:
An unhandled exception has occurred: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information. (fc7986d0)
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Researching this it appears to relate to a missing dll or mismatched version, and that I should look at the LoaderExceptions property to get more info, but I'm not sure how to do that in this instance. The log entry is created just from setting up the loggerFactory in the Configure() method of Startup.cs.
I tried adding an IExceptionFilter ActionFilter implementation and reading the LoaderExceptions property if the exception is of type ReflectionTypeLoadException, but it doesn't get hit when ran on the server.
Is there a way to drill down into the Exception to read the LoaderExceptions property (in a production environment, there is no error when running in Visual Studio so debugging didn't help), or else another way to troubleshoot the original error to determine what is wrong with the server setup?
Instead of using IExceptionFilter, I wrote my own Middleware for catching this sort of exception and was able to log each exception from the LoaderExceptions property and determine what my problem is. Here is what I added to log the LoaderExceptions:
public class ExceptionCatchMiddleware
{
private readonly RequestDelegate _delegate;
private readonly ILogger _logger;
public ExceptionCatchMiddleware(RequestDelegate requestDelegate, ILogger<ExceptionCatchMiddleware> logger)
{
_delegate = requestDelegate;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
try
{
await _delegate(context);
}
catch (ReflectionTypeLoadException e)
{
foreach (Exception ex in e.LoaderExceptions)
{
_logger.LogCritical(ex.Message + Environment.NewLine + ex.StackTrace);
}
}
}
}
And then I just needed to add the Middleware to the Configure() method in Startup.cs:
app.UseMiddleware<ExceptionCatchMiddleware>();
In my case it was a missing dll that wasn't included in the project but since it was in my dev machine's GAC it ran there just fine.

Invalid Token when confirming email address - Asp.Net Core

I'm occasionally getting an "Invalid Token" error from my call to
userManager.ConfirmEmailAsync(user, token) . I've narrowed down the problem to the fact that my 2 web servers are sitting behind a load balancer, and the web server that generated the token isn't always the web server that is attempting to confirm the token. I had a similar problem with anti-forgery tokens in a different web site, which I fixed by persisting the data protection key to disk and sharing it between the web servers, so I tried a similar approach here.
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\API"));
I then copied the key to the same folder in my other web server but still wasn't successful. Debugging through the AspNetCore.Identity code I can see an exception thrown on the call to
var unprotectedData = Protector.Unprotect(Convert.FromBase64String(token))
in the DataProtectorTokenProvider class. the catch block for the exception in Microsoft's code is simply
catch
{
// Do not leak exception
}
so I decided to inject an IDataProtector into my own Controller and try making that call myself.
public UserController(Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager, Microsoft.AspNetCore.Identity.RoleManager<IdentityRole> roleManager,
ILoggerFactory loggerFactory,
IDataProtectionProvider dataProtectionProvider)
{
Protector = dataProtectionProvider.CreateProtector("DataProtectorTokenProvider");
}
try
{
var unconverted = Convert.FromBase64String(request.EmailConfirmationToken);
var unprotectedData = Protector.Unprotect(unconverted);
}
catch (Exception e)
{
}
I can now catch the exception thrown on the Unprotect call and it's:
The payload was invalid
Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(Byte* pbCiphertext, UInt32 cbCiphertext, Byte* pbAdditionalAuthenticatedData, UInt32 cbAdditionalAuthenticatedData)\r\n at Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment1 ciphertext, ArraySegment1 additionalAuthenticatedData)\r\n at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)\r\n at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)\r\n at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)\r\n at VTR.API.Controllers.UserController.d__16.MoveNext() in C:\Projects\Brewster.Travel\src\cres\trunk\VTR.API\src\VTR.API\Controllers\UserController.cs:line 409
If I make that call with a token generated on the same server then it gets unprotected successfully. I obviously have some problem with how I'm attempting to share my data protection keys, if anyone could shed some light on my problem I would appreciate it.
I managed to get this working thanks to the documentation here: https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview
I needed to add a call to SetApplicationName() in ConfigureServices:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\someDirectory"))
.SetApplicationName("myApplicationName");

WCF RIA Service with Unity 3.5.1.0

I'm trying to Use this Blog for WCF RIA Applcation . So I Create a Silverlight Nevigation Applciation which gave me 2 projects abs & abs.Web
More I create 3 project in solution :
abs.Data (c#), DbContext Implemeantion of Repository Interfaces +Factory to provide What user want.
abs.Data.Contarct (c#) Interfaces for Operations Repository
abs.Data.Model (c#) - Contains POCO - EF 6
Now I created A wcf Service in abs.Web project which have constructor injection of a Repository to get my job done in operation contracts.
So I tried using Unity here under the guidence with below blog
http://jamesheppinstall.wordpress.com/2012/06/20/windows-communication-foundation-resolving-wcf-service-dependencies-with-unity/
Now I'm getting
The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
**Stack Trace: **
[InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.]
System.ServiceModel.Dispatcher.InstanceBehavior..ctor(DispatchRuntime dispatch, ImmutableDispatchRuntime immutableRuntime) +12761206
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime..ctor(DispatchRuntime dispatch) +173
System.ServiceModel.Dispatcher.DispatchRuntime.GetRuntimeCore() +85
System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpened() +148
System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +321
System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +139
System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +310
System.ServiceModel.Channels.CommunicationObject.Open() +36
System.ServiceModel.HostingManager.ActivateService(ServiceActivationInfo serviceActivationInfo, EventTraceActivity eventTraceActivity) +91
System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity) +598
[ServiceActivationException: The service '/DomainServices/UserWcfService.svc' cannot be activated due to an exception during compilation. The exception message is: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host..]
System.Runtime.AsyncResult.End(IAsyncResult result) +499812
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +178
System.ServiceModel.Activation.ServiceHttpHandler.EndProcessRequest(IAsyncResult result) +6
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +129
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18446
My all classes are same as like Blog.
WCF Ria has its own factory.
Simply put
public class MyDomainServiceFactory : IDomainServiceFactory
{
#region IDomainServiceFactory Members
public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context)
{
try
{
if (!typeof (DomainService).IsAssignableFrom(domainServiceType))
{
throw new ArgumentException(String.Format("Cannot create an instance of {0} since it does not inherit from DomainService", domainServiceType), "domainServiceType");
}
if (IoC.IsRegistered(domainServiceType))
{
var dmnService = (DomainService) IoC.Resolve(domainServiceType);
dmnService.Initialize(context);
return dmnService;
}
else
{
//if the IoC container doesn't know the service, simply try to call its default constructor
//could throw proper exception as well
var dmnService = (DomainService) Activator.CreateInstance(domainServiceType);
dmnService.Initialize(context);
return dmnService;
}
}
catch (Exception ex)
{
ExceptionHandler.HandleException(ex);
return null;
}
}
public void ReleaseDomainService(DomainService domainService)
{
domainService.Dispose();
}
#endregion
}
and somewhere on your bootstrapping code add
DomainService.Factory = new MyDomainServiceFactory();
of course, the word IoC in the factory identify the unityContainer (is actually a static façade against it)

Visual Studio Express 2012 - Silverlight-Enabled WCF Service?

I just started a new Silverlight project with Visual Studio Express 2012 for Web.
I created a Silverlight-enabled WCF service to access a SQL Server database, with EF 5.
The problem I'm having is that the service doesn't seem to be able to return any entity retrieved from the database. A new entity or any old object is returned just fine, but when I try to return an entity from the context I get the following exception:
{System.ServiceModel.CommunicationException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassa.<EndGetResponse>b__9(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass4.<BeginOnUI>b__0(Object sendState)
--- End of inner exception stack trace ---
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
--- End of inner exception stack trace ---
at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
at NewProj.DataSvcRef.DataServiceClient.DataServiceClientChannel.EndGetAgency(IAsyncResult result)
at NewProj.DataSvcRef.DataServiceClient.NewProj.DataSvcRef.DataService.EndGetAgency(IAsyncResult result)
at NewProj.DataSvcRef.DataServiceClient.OnEndGetAgency(IAsyncResult result)
at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)}
The service method code couldn't be simpler:
[OperationContract]
public Contact GetContact(int aID)
{
Contact res = null;
using (var db = new OFBEntities())
{
try
{
res = db.Contacts.Find(aID);
}
catch (Exception ex)
{
res = null;
}
return res;
}
}
As I mentioned, if I return a newly created object (return new Contact(){ name="test contact};), or return a type that is not in context (say an integer for example), everything works fine.
Is this a limitation of the express version, or am I forgetting some settings? In the past I have created some Silverlight apps that consumed data services with VS 2010, Silverlight 4, and I don't remember having to set anything special, but maybe I just forgot that I did?
Any help is appreciated!
EDIT:
Could it have anything to do with DbContext and the way it is serialized? I've never used DbContext before, I always used the default ObjectContext in EF 4...
EDIT2: SOLUTION
It's been a while, but I had other things to work :o)
In case anybody is in the same boat, the problem was in the serialization by the service. DbContext by default creates proxies, which don't agree with serialization. I am not sure why yet - indeed, I need to educate myself about those proxies - but disabling them solves my serialization issue.
Thanks for the comment Pawel, I mistakenly thought my serialization was going OK, rechecking the server-side error put me back on the right track.
The problem was with automatic proxy creation by the DBContext, which interfered with the serialization.
Proxies are on by default in DBContext, you can disable them in the class constructor
this.Configuration.ProxyCreationEnabled = false;
or after creating an instance of your DBContext
using (var db = new myDBContext())
{
db.Configuration.ProxyCreationEnabled = false;
...
}
Not sure why yet, but it works. Time to go read up on that!