RIA Services: Server process returns multiple entities but Client shows 1 entity duplicated - silverlight-4.0

I am running into an issue where RIA Services returns 3 entities from the server (I have verified while debugging on the server process, and have verified via Fiddler that the service is in face returning 3 entities.
I am using MVVM so I am calling Load on the client side using a helper function that I borrowed from a Shawn Wildermuth sample: Here's that code:
// Generic query handling
protected void PerformQuery<T>(DomainContext dc, string name, EntityQuery<T> qry, EventHandler<EntityResultsArgs<T>> evt) where T : Entity
{
dc.Load<T>(qry,(r) =>
{
if (evt != null)
{
try
{
if (r.HasError)
{
evt(this, new EntityResultsArgs<T>(r.Error));
}
else if (r.Entities.Count() > 0)
{
evt(this, new EntityResultsArgs<T>(r.Entities));
}
}
catch (Exception ex)
{
evt(this, new EntityResultsArgs<T>(ex));
}
}
}, null);
}
EntityResultsArgs is a simple class that exposes an exception property (called Error) and a Results property (containing the results if we got any).
On the server we are mapping the result using AutoMapper to our exposed Domain Classes and this particular service call returns IEnumerable.
What am I missing (or what more would help someone figure this out).
Thanks!

Yep, the problem is now confirmed. I was retrieving 3 entities back from the service all with an Id (aka the "[Key]" value) of 0.

Related

UserNamePasswordValidator and Session Management

I'm using WCF custom Validator with HTTPS (.NET 4.5). Validate on success returns Customer object which I would like to use later. Currently I'm able to do it with Static variables which I like to avoid if possible. I tried to use HttpContext which becomes null in main thread. My understanding Validate runs under different thread. Is there any way I could share session info without involving DB or File share. See related threads here and here.
In Authentication.cs
public class CustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//If User Valid then set Customer object
}
}
In Service.cs
public class Service
{
public string SaveData(string XML)
{
//Need Customer object here. Without it cannot save XML.
//HttpContext null here.
}
}
I can suggest you an alternative approach. Assuming that the WCF service is running in ASP.Net compatibility mode and you are saving the customer object to session storage. Create a class such as AppContext
The code would look something like this
public class AppContext {
public Customer CurrentCustomer {
get {
Customer cachedCustomerDetails = HttpContext.Current.Session[CUSTOMERSESSIONKEY] as Customer;
if (cachedCustomerDetails != null)
{
return cachedCustomerDetails;
}
else
{
lock (lockObject)
{
if (HttpContext.Current.Session[CUSTOMERSESSIONKEY] != null) //Thread double entry safeguard
{
return HttpContext.Current.Session[CUSTOMERSESSIONKEY] as Customer;
}
Customer CustomerDetails = ;//Load customer details based on Logged in user using HttpContext.Current.User.Identity.Name
if (CustomerDetails != null)
{
HttpContext.Current.Session[CUSTOMERSESSIONKEY] = CustomerDetails;
}
return CustomerDetails;
}
}
}
}
The basic idea here is to do lazy loading of data, when both WCF and ASP.Net pipelines have executed and HTTPContext is available.
Hope it helps.
Alright this should have been easier. Since the way UserNamePasswordValidator works, I needed to use custom Authorization to pass UserName/Password to the main thread and get customer info again from the database. This is an additional DB call but acceptable workaround for now. Please download code from Rory Primrose's genius blog entry.

WebApi returning wrong status code

I have an operation handler that checks for authentication and throws an exception when authentication fails using
throw new WebFaultException(HttpStatusCode.Unauthorized);
However this still returns a 404 Not Found status code to the client/test client.
This is my operation handler
public class AuthOperationHandler : HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
{
RequireAuthorizationAttribute _authorizeAttribute;
public AuthOperationHandler(RequireAuthorizationAttribute authorizeAttribute) : base("response")
{
_authorizeAttribute = authorizeAttribute;
}
protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
{
IPrincipal user = Thread.CurrentPrincipal;
if (!user.Identity.IsAuthenticated)
throw new WebFaultException(HttpStatusCode.Unauthorized);
if (_authorizeAttribute.Roles == null)
return input;
var roles = _authorizeAttribute.Roles.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
if (roles.Any(role => user.IsInRole(role)))
return input;
throw new WebFaultException(HttpStatusCode.Unauthorized);
}
}
Am I doing something wrong?
I have good and bad news for you. The framework your are using has evolved into ASP.NET Web API. Unfortunately, OperationHandlers no longer exist. Their closest equivalent are ActionFilters.
Having said that, WCF Web API never supported throwing WebFaultException, that is a vestige of WCF's SOAP heritage. I think the exception was called HttpWebException, however, I never used it, I just set the status code on the response.

Per- request based Object Context and Complied Query Performance with Entity Framework

I'm currently working with WCF services application and we've created per request based Object Context of Entity framework. In the entity framework queries, we've used Complied Query mechanism, however, expected performance could not be achieved at the moment. I suspect it is due to the nature of Object Context(Per request based),as Complied queried depends on Object Context. Is it so?
Code Sample
private static readonly Func<MyContext, IQueryable<Order>> _compiledObjectQuery = CompiledQuery.Compile<MyContext, IQueryable<Order>>(
(ctx) => from Order in ctx.Orders
.Include("OrderType")
.Include("OrderLines")
select Order
);
protected override IQueryable<Order> OrderQuery
{
get { return _compiledObjectQuery.Invoke(Context); }
}
Context Creating
public OPDbContext DbContext
{
get
{
if(_dbConext == null)
{
_dbConext = new OPDbContext(Context, true);
}
return _dbConext;
}
}
Castle is used to inject Object Context per request base

WP7 EndPointNotFound exception for transporting an entity over WCF?

So I'm experiencing a strange error. I have a WP7 application that has a service reference to a WCF service I wrote. The WCF has an entity model for the database.
Basically what I want to happen, is when a user logs in on the phone, the matching SystemUser entry is returned from the WCF service. SystemUser is a table in the db.
On the WCF service side I have the following:
public SystemUser UserLogin(string emailAddress, string userPassword)
{
Regex emailRegex = new Regex(#"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
if (emailRegex.IsMatch(emailAddress) && !string.IsNullOrEmpty(userPassword))
{
using (var context = new DBEntities())
{
var users = context.SystemUsers.Where(su => su.EmailAddress.ToLower().Trim() == emailAddress.ToLower().Trim());
// there should only be one user in here!
if (users.Count() <= 0)
{
return null;
}
else
{
return users.FirstOrDefault();
}
}
}
return null;
}
Nothing too hardcore. And when the phone calls that method, it throws an EndPointNotFoundException when trying to return the SystemUser object. "There was no endpoint listening at http://localhost:49676/Service1.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details." The inner exception is: "{"The remote server returned an error: NotFound."}"
The generated code that has this problem is here:
public ServiceProxy.UserLoginResponse EndUserLogin(System.IAsyncResult result) {
object[] _args = new object[0];
PhoneApp.ServiceProxy.UserLoginResponse _result = ((PhoneApp.ServiceProxy.UserLoginResponse)(base.EndInvoke("UserLogin", _args, result)));
return _result;
}
It basically looks like it cannot transport the entity? Any ideas? I thought I didn't need to use POCO objects?
Do you have [OperationContract] before Method Name?
http://localhost:49676/Service1.svc is working in browser?
Ok what I did to fix this issue is to right click on blank space in the edmx designer and choose "Add Code Generated Item". From there I picked ADO.NET Self-Tracking Entity Generator. Works beautifully now!

Can a DomainService return a single custom type?

I would like a method on my in my domain service similar to:
public SystemState GetSystemStatus()
{
return new SystemStatus
{
InterestingStatusValue1 = 1223,
OtherInterstingStatusValue = "abc",
}
}
That doesn't work. Nothing is auto-generated for the Silverlight client app. Howerver if I make this an IQueryable method, then I get something generated on the client. I'll get a SystemStates property and a Query method on the context object.
Is there no way to make this a simple WCF call? I suppose I could a WCF Silverlight Enabled service to my RIA Web site, and then setting a Service Reference (that can't be right?) (and why can't I see the Services Reference in the Silverlight app?)
On first blush it seems that RIA services forces a very data-centric/easy CRUD which is great for table editors, but not so much for LOB applications that go behind drag on a datagrid and you're done.
You can return just one entity using an attribute (assuming that SystemState is your entity):
Ex:
[Query(IsComposable = false)]
public SystemState GetSystemStatus()
{
return new SystemStatus
{
InterestingStatusValue1 = 1223,
OtherInterstingStatusValue = "abc",
}
}
Remember that this is still a query and Ria Services will generate a method in your DomainContext like:
EntityQuery<SystemState> GetSystemStatusQuery()
Use it like a normal EntityQuery, but keep in mind that you can't perform query operations (sorting or filtering) on the returned object.
If you want to execute an operation on server, try using the [Invoke] attribute. Ex:
[Invoke]
public SystemState GetSystemStatus()
{
return new SystemStatus
{
InterestingStatusValue1 = 1223,
OtherInterstingStatusValue = "abc",
}
}
I don't know how complex your return type can be, but I guess if it can be serialized, it will work (not sure).