Mvvmcross tombstoning - always return null values - windows-runtime

I tried two approaches:
1.
public class SavedState
{
public string Data1 { get; set; }
public string Data2 { get; set; }
}
public void ReloadState(SavedState state)
{
//Data1 and Data2 always have null values.
}
public SavedState SaveState() {
return new SavedState
{
Data1 = "AAAA",
Data2 = "BBBB"
};
}
2.
protected override void ReloadFromBundle(IMvxBundle state)
{
base.ReloadFromBundle(state);
//state.Data has 0 elements.
}
protected override void SaveStateToBundle(IMvxBundle bundle)
{
bundle.Data["Data1"] = "AAAA";
bundle.Data["Data2"] = "BBBB";
base.SaveStateToBundle(bundle);
}
What am I doing wrong? The ReloadStateand ReloadFromBundle methods are called but with null parameters.
I have only Windows Store target, with custom presenter which shows view this way:
_rootFrame.Navigate(GetViewType(request), request);

Yesterday I had similar issue.
I used this code to show ViewModel with parameter:
ShowViewModel<UserAccountViewModel>(new UserAccountViewModelParams{ FromLogin = true });
and tombstoning behaved exactly like in your case.
When I changed it to:
ShowViewModel<UserAccountViewModel>();
it worked.
I guess it's MVX error.

Related

"You should only initialize MvxBindingSingletonCache once" error when have several test classes

I run into a strange exception. In my test project, I use Moq, xUnit, and MvvmCross.Tests.
When I run my tests from one class - everything works just fine. When I run tests from 2 classes I get MvvmCross.Exceptions.MvxException.
I have 2 identical (initialization is identical) classes VitalsDataTests and GetReimbursedTests:
public class VitalsDataTests : MvxIoCSupportingTest
{
public VitalsDataTests()
{
base.Setup();
}
protected MockDispatcher MockDispatcher
{
get;
private set;
}
protected override void AdditionalSetup()
{
MockDispatcher = new MockDispatcher();
Ioc.RegisterSingleton<IMvxViewDispatcher>(MockDispatcher);
Ioc.RegisterSingleton<IMvxMainThreadDispatcher>(MockDispatcher);
Ioc.RegisterSingleton<IMvxMainThreadAsyncDispatcher>(MockDispatcher);
}
...
}
Here is my MockDispatcher:
public class MockDispatcher
: MvxMainThreadDispatcher
, IMvxViewDispatcher
{
public readonly List<MvxViewModelRequest> Requests;
public readonly List<MvxPresentationHint> Hints;
public MockDispatcher()
{
if (Hints == null) Hints = new List<MvxPresentationHint>();
if (Requests == null) Requests = new List<MvxViewModelRequest>();
}
public override bool IsOnMainThread { get; }
public Task<bool> ChangePresentation(MvxPresentationHint hint)
{
Hints.Add(hint);
return Task.FromResult(true);
}
public async Task ExecuteOnMainThreadAsync(Action action, bool maskExceptions = true)
{
await Task.Run(action);
}
public async Task ExecuteOnMainThreadAsync(Func<Task> action, bool maskExceptions = true)
{
await Task.Run(action);
}
public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{
action();
return true;
}
public Task<bool> ShowViewModel(MvxViewModelRequest request)
{
Requests.Add(request);
return Task.FromResult(true);
}
}
What I tried:
Clearing MvxSingleton and MvxBindingSingletonCache singletons in the constructor of each class before I call base.Setup():
MvxSingleton.ClearAllSingletons();
MvxBindingSingletonCache.ClearAllSingletons();
Not sure what I'm doing wrong.
thank you for your help.
I was able to solve this error by adding XUnit Collection Attribute for each test class, like this:
[Collection("ViewModels")]
public class GetReimbursedTests : BaseTest
{
...
}

jQuery Bootgrid - Ajax Sort Parameter with ASP.NET MVC Actions

I managed to create an ApiController retrieving data from my repositories, and populating a grid in my view through Bootgrid with Ajax. This is an example of request data sent to Api's Action, given by their Docs here (look for POST Body Request tab):
current=1&rowCount=10&sort[sender]=asc&searchPhrase=&id=b0df282a-0d67-40e5-8558-c9e93b7befed
Here is an example URL:
http://localhost/api/SomeController?current=1&rowCount=10&sort%5BName%5D=asc&searchPhrase=&id=b0df282a-0d67-40e5-8558-c9e93b7befed
I created two Helper classes to handle data I must return as response, and sort data (as it's an array):
public class SortData
{
public string Field { get; set; } // FIeld Name
public string Type { get; set; } // ASC or DESC
}
public class BootgridResponseData<T> where T: class
{
public int current { get; set; } // current page
public int rowCount { get; set; } // rows per page
public IEnumerable<T> rows { get; set; } // items
public int total { get; set; } // total rows for whole query
}
Therefore, my action is as follow:
public BootgridResponseData<SomeViewModel> Get(int current, int rowCount, List<SortData> sort, string searchPhrase, string id)
{
// get items and return a bootgrid response data with them...
}
The method is invoked and all parameters come with data properly, except sort, which is always null.
What kind of parameter should I expect for this? I also tried to put object but it comes null anyway.
After learning a bit more, I saw Bootgrid has a requestHandler setting which allows you to manipulate data sent to server.
I did it in my javascript like this:
var grid = $("#my-grid").bootgrid({
ajax: true,
rowCount: 10,
ajaxSettings: {
method: "POST",
cache: true
},
requestHandler: function (request) {
// Scan the original sort object from Bootgrid...
// and populate an array of "SortData"...
request.sortItems = [];
if (request.sort == null)
return request;
for (var property in request.sort) {
if (request.sort.hasOwnProperty(property)) {
request.sortItems.push({ Field: property, Type: request.sort[property] });
}
}
return request;
},
url: "/api/FooApi"
});
Then I created my post action in API like this:
public class FooApiController : ApiController
{
[HttpPost]
public BootgridResponseData<FooModel> Get(BootgridRequestData model)
{
// This would come from some data store, using the request params...
// I use PagedList to make pagination easier...
IPagedList<FooModel> itemsPaged = store.GetPagedFoo();
// Then return the response with data...
return new BootgridResponseData<FooModel>()
{
current = model.current,
rowCount = model.rowCount,
rows = itemsPaged,
total = itemsPaged.TotalItemCount
};
}
}
The BootgridResponseData has already been shown in my question. I just added a BootgridRequestData which the following structure:
public class BootgridRequestData
{
public int current { get; set; }
public int rowCount { get; set; }
public string searchPhrase { get; set; }
public IEnumerable<SortData> sortItems { get; set; }
}
Then I could even use my original SortData helper class:
public class SortData
{
public string Field { get; set; } // FIeld Name
public string Type { get; set; } // ASC or DESC
}
I've struggled with this as well. You are overthinking it. It's nice to create simple models to handle the post call from jquery-bootgrid, but you can also just use simple parameters in the post method. As for the sort, it looks like a Key-Value pair, but that doesn't serialize properly.
I ended up trying a Dictionary object and it works.
Here is my signature:
[HttpPost]
public async Task<ActionResult> GetActiveDogs(int? current, int? rowCount,
Dictionary<string, string> sort, string searchPhrase = null)
I had the same problem passing the sort options to my webservice. The Dictionary object did not solve my problem either.
To solve it, I created a class holding string properties for each field I wanted to pass through the bootgrid sort options. See code excerpt
class TestSort
{
public string field1 { get; set; }
public string field2 { get; set; }
...
}
I use this class as the sort options parameter in my webservice. All fields in this class that are referred to by the bootgrid options are set to "ASC" or "DESC". The others remain null.
I added an 'orderBy' property to this class that returns an orderby clause for the fields that are not null.
Approch1.
consider you have table with columns "col1, col2, col3, ...".
you can use:
public ActionType Get(int current, int rowCount, Sort sort, string searchPhrase) {
//sort.col1 == 'asc' (consider sorted by col1 in ascending order)
}
public class Sort
{
public string col1 { get; set; }
public string col2 { get; set; }
public string col3 { get; set; }
//... other columns
}
Approach 2.
You can use remove you parameters and parse request data manually. i used post here instead of get.
[HttpPost]
public object Post(){
string jsonContent = Request.Content.ReadAsStringAsync().Result;
Dictionary<string, string> keyvalues = new Dictionary<string, string>();
string[] keyvalue_strings = jsonContent.Split('&');
string sort_column = "";
string sort_direction = "";
for (var i = 0; i< keyvalue_strings.Length; i++)
{
var a = keyvalue_strings[i].Split('=');
a[0] = a[0].Replace("%5B", "[").Replace("%5D", "]");
keyvalues.Add(a[0], (a[1]));
if (a[0].Contains("sort"))
{
sort_column = a[0].Replace("sort[", "").Replace("]", "");
sort_direction = a[1];
}
}
//now you have keyvalues, sort_column, sort_direction.
//...
}

Service Stack POST-Request Body-Format / Transformation

iam using a RequestClass with the Route anotation to call a Json-Client POST method.
Now, while the paramters are structured like this
public class GetTicketRequest: IReturn<JsonObject>
{
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
}
The BackendAPI needs them to be nesten in "data" in the json request, so more like
{
"data":[
{"cartid":123,
"priceId":11}]
}
Is there any way to transfrom the request object for the body before calling
JsonServiceClient _restClient = new JsonServiceClient(baseUrl);
JsonObject oneResponse = _restClient.Post(options);
This solution is useful where many DTOs require to be wrapped & converted, and is highly reusable, with no changes to your existing DTOs.
You can convert the requests of the JsonServiceClient by overriding the methods that handle preparing the requests for sending. Which means implementing your own extended JsonServiceClient as given below.
If you want to do this for all verbs then you override it's Send<TResponse> methods (otherwise, if it's just for POST then uncomment the commented out code, and remove the Send methods).
public class MyJsonServiceClient : JsonServiceClient
{
public Dictionary<Type, Func<object, object>> DtoConverters = new Dictionary<Type, Func<object, object>>();
public MyJsonServiceClient() {}
public MyJsonServiceClient(string baseUri) : base(baseUri) {}
public MyJsonServiceClient(string syncReplyBaseUri, string asyncOneWayBaseUri) : base(syncReplyBaseUri, asyncOneWayBaseUri) {}
public override TResponse Send<TResponse>(object request)
{
return base.Send<TResponse>(ConvertRequest(request));
}
public override TResponse Send<TResponse>(string httpMethod, string relativeOrAbsoluteUrl, object request)
{
return base.Send<TResponse>(httpMethod, relativeOrAbsoluteUrl, ConvertRequest(request));
}
/*
public override TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object requestDto)
{
return base.Post(relativeOrAbsoluteUrl, ConvertRequest(requestDto));
}
*/
object ConvertRequest(object request)
{
Type dtoType = request.GetType();
return (DtoConverters.ContainsKey(dtoType)) ? DtoConverters[dtoType](request) : request;
}
}
Usage:
So given this DTO:
[Route("/test", "POST")]
public class TicketRequest : IReturnVoid
{
public string CartId { get; set; }
public string PriceId { get; set; }
}
You simply add the converter:
var client = new MyJsonServiceClient("http://localhost:9000");
// Simple converter for TicketRequest
client.DtoConverters.Add(typeof(TicketRequest), dto => {
var d = (TicketRequest)dto;
return new {
data = new {
CartId = d.CartId.ToInt(),
PriceId = d.PriceId.ToInt()
}
};
});
client.Post(new TicketRequest { CartId = "123", PriceId = "456" });
i solved this issue using a typed data property
public class GetTicketRequest: IReturn<JsonObject>
{
public class TicketCreateData
{
public int priceId {
get;
set;
}
}
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
public List<TicketCreateData> data {
get {
var list = new List<TicketCreateData>();
list.Add(new TicketCreateData {
priceId = this.PriceId.ToInt()
});
return list;
}
set {
data = value;
}
}
}
To notes on this:
if neede, use DataContract/DataMember(Name="") to rename fields or only do partial serializing
Do never use structs for, like in this case, the data class - they are not serializeable at all
in my spefici case data even needs to be an array, thats why i used the list

Entity Framework type case generic in predicate

I am working on updating to a more manageable repository pattern in my MVC 4 project that uses Entity Framework code first. I've integrated a generic base repository class that will do basic CRUD operations so I don't have to implement these in each repository I create. I have ran into an issue where my All method needs to filter there query by a deleted flag if the entity is a type of TrackableEntity. Since the Entity is generic in the base repository I am attempting to cast is to a type of TrackableEntity in the where which just results in the following error message.
The 'TypeAs' expression with an input of type 'NameSpace.Models.ClientFormField' and a check of type 'NameSpace.Models.TrackableEntity' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.
This error makes complete since and I understand why the code I have is not working but I am trying to find a way to filter out deleted items without having to override this method in all of my repositories. The code I have for my All method is below.
public virtual IEnumerable<T> All()
{
if (typeof(T).IsSubclassOf(typeof(TrackableEntity)))
return dbSet.Where(e => !(e as TrackableEntity).IsDeleted).ToList();
return dbSet.ToList();
}
I know that I can do the following
public virtual IEnumerable<T> All(Expression<Func<T, bool>> predicate = null)
{
if (predicate != null)
return dbSet.Where(predicate).IsDeleted).ToList();
return dbSet.ToList();
}
And then add this to all of my repositories
public override IEnumerable<CaseType> All(Expression<Func<CaseType,bool>> predicate = null)
{
if (predicate == null)
predicate = e => !e.IsDeleted;
return base.All(predicate);
}
The problem I have with this is that I am duplicating code, this is basically a copy and paste into all of my repositories which defeats the purpose of changing to this new repository pattern. I made the switch to end duplicated code in my repositories.
Here is an example of one of my entities.
public class CaseType : TrackableEntity, IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public bool InUse { get; set; }
public bool IsValid { get { return !this.Validate(null).Any(); } }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (String.IsNullOrEmpty(Name))
yield return new ValidationResult("Case Type name cannot be blank", new[] { "Name" });
//Finish Validation Rules
}
}
And the TrackableEntity
public abstract class TrackableEntity
{
public bool Active { get; set; }
public bool IsDeleted { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
Any help on this would be much appreciated.
I finally got a solution working that I am happy with. I ended up making 2 generic repositories. One that is the base repository which deals with all of the calls to the database for my BaseEntity which all entities inherit from. Then I made my 2nd generic repo which is inherits BaesEntity and overrides a few methods to handle the needs of my TrackableEntities. In the end this does what I want by handling the filtering of soft deleted items from within the repo and also gives me more flexibility with the TrackableEntity.
BaseRepository -
public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
{
private readonly IAppDb _db;
private readonly IDbSet<T> _dbSet;
public BaseRepository(IAppDb db)
{
_db = db;
_dbSet = Lwdb.Set<T>();
}
protected IAppDb Lwdb
{
get { return _db; }
}
#region IBaseRepository<T> Members
public virtual T GetById(int id)
{
return _dbSet.Find(id);
}
public virtual T Add(T entity)
{
_dbSet.Add(entity);
_db.Commit();
return entity;
}
public virtual bool Any(Expression<Func<T, bool>> expression)
{
return _dbSet.Any(expression);
}
public virtual void Delete(T entity)
{
_dbSet.Remove(entity);
_db.Commit();
}
public virtual IEnumerable<T> All()
{
return _dbSet.ToList();
}
public virtual T Update(T entity, bool attachOnly = false)
{
_dbSet.Attach(entity);
_db.SetModified(entity);
if (!attachOnly) _db.Commit();
return entity;
}
#endregion
protected User GetCurrentUser()
{
return
_db.Set<User>().Find(HttpContext.Current != null ? ((User) HttpContext.Current.Session["User"]).Id : 1);
}
BaseTrackableEntityRepository -
public class BaseTrackableEntityRepository<T> : BaseRepository<T>, IBaseTrackableEntityRepository<T>
where T : TrackableEntity
{
private readonly IAppDb _db;
private readonly IDbSet<T> _teDB;
public BaseTrackableEntityRepository(IAppDb db)
: base(db)
{
_db = db;
_teDB = _db.Set<T>();
}
#region IBaseTrackableEntityRepository<T> Members
public virtual T SetDeleteFlag(int id)
{
var entity = _teDB.Find(id);
if (entity == null) return null; //throw exception
entity.IsDeleted = true;
entity.DateModified = DateTime.Now;
entity.ModifiedBy = GetCurrentUser();
return Update(entity);
}
public override IEnumerable<T> All()
{
return _teDB.Where(e => !e.IsDeleted).ToList();
}
public override T Add(T entity)
{
var curUser = GetCurrentUser();
entity.CreatedBy = curUser;
entity.ModifiedBy = curUser;
entity.DateCreated = DateTime.Now;
entity.DateModified = DateTime.Now;
entity.Active = true;
entity.IsDeleted = false;
_teDB.Add(entity);
_db.Commit();
return entity;
}
public override T Update(T entity, bool attachOnly = false)
{
InsertTeData(ref entity);
entity.ModifiedBy = GetCurrentUser();
entity.DateModified = DateTime.Now;
_teDB.Attach(entity);
_db.SetModified(entity);
if (!attachOnly) _db.Commit();
return entity;
}
public virtual T SetStatus(int id, bool status)
{
var entity = _teDB.Find(id);
if (entity == null) return null;
entity.Active = status;
return Update(entity);
}
#endregion
private void InsertTeData(ref T entity)
{
if (entity == null || entity == null) return;
var dbEntity = GetById(entity.Id);
if (dbEntity == null) return;
_db.Detach(dbEntity);
entity.CreatedBy = dbEntity.CreatedBy;
entity.DateCreated = dbEntity.DateCreated;
entity.ModifiedBy = dbEntity.ModifiedBy;
entity.DateModified = dbEntity.DateModified;
}

WCF Data Services 5.0 Workaround for returning POCOs?

I'm pretty sure it hasn't, but apologies if this question has already been asked. And additional apologies if this is just flat out a dumb question but I feel like I'm either completely missing something or have the right idea and just need some backup for my own sanity.
I've been implementing WCF Data Services 5.0 in our application and am having no issues with read operations returning entity objects.
Unfortunately there is that nasty limitation when it comes to service operations that they can only return primitive types (See MSDN). It's very annoying given that it has no problems with the entity objects.
I know that one workaround is to create a "dummy" complex type since WCFDS will recognize that but I don't want to just throw random POCOs into my data model that aren't actually in the database.
So the solution that occurred to me was to create an extension method for my objects that can serialize them into JSON strings to be returned by the service. My question is; are there any compelling arguments why I shouldn't do this or can anyone suggest any better alternatives?
Edit: Additional information to clarify my current issues
I created a very simple example of what I'm doing that originally raised this question. My service class follows first:
[JsonpSupportBehavior]
public partial class SchedulingService : DataService<ChronosDataContext>, ISchedulingService
{
public static void InitializeService(DataServiceConfiguration config)
{
#if DEBUG
config.UseVerboseErrors = true;
#endif
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.SetServiceOperationAccessRule(
"TestService",
ServiceOperationRights.All);
}
[WebGet]
public SchedulingResult TestService(
string testParam1,
string testParam2)
{
// NOTE: I never use the params, they're just there for this example.
SchedulingResult result = SchedulingResult.Empty;
result.Status = OperationStatus.Success;
result.ResponseID = Guid.NewGuid();
result.AffectedIDs = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7 });
result.RecordsAffected = 10;
return result;
}
}
Attempting to access this service using my browser, I get the following request error:
The server encountered an error processing the request. The exception message is
'Unable to load metadata for return type
'Chronos.Services.SchedulingResult' of method
'Chronos.Services.SchedulingResult TestService(System.String, System.String)'.'.
See server logs for more details.
The exception stack trace is:
at System.Data.Services.Providers.BaseServiceProvider.AddServiceOperation(MethodInfo method, String protocolMethod)
at System.Data.Services.Providers.BaseServiceProvider.AddOperationsFromType(Type type)
at System.Data.Services.Providers.BaseServiceProvider.LoadMetadata()
at System.Data.Services.DataService`1.CreateMetadataAndQueryProviders(IDataServiceMetadataProvider& metadataProviderInstance, IDataServiceQueryProvider& queryProviderInstance, BaseServiceProvider& builtInProvider, Object& dataSourceInstance)
at System.Data.Services.DataService`1.CreateProvider()
at System.Data.Services.DataService`1.HandleRequest()
at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Below are the classes that make up the SchedulingResult that I'm trying to return:
public class SchedulingResult : ServiceInvocationResponse
{
public SchedulingResult()
: base()
{
this.Payload = new object[]
{
new List<int>(),
new List<int>()
};
}
public List<int> AffectedIDs
{
get { return (List<int>)Payload[0]; }
set { Payload[0] = value; }
}
public List<int> FailedIDs
{
get { return (List<int>)Payload[1]; }
set { Payload[1] = value; }
}
public static SchedulingResult Empty
{
get { return new SchedulingResult(); }
}
}
public class ServiceInvocationResponse : AbstractJsonObject<ServiceInvocationResponse>
{
public ServiceInvocationResponse()
{
this.Status = OperationStatus.Unknown;
this.Severity = ErrorSeverity.None;
}
public virtual int RecordsAffected { get; set; }
public virtual Exception ErrorObject { get; set; }
internal virtual object[] Payload { get; set; }
}
public abstract class AbstractJsonObject<TBaseType>
{
public virtual object Deserialize(string source)
{
return JsonConvert.DeserializeObject(source);
}
public virtual T Deserialize<T>(string source)
{
return JsonConvert.DeserializeObject<T>(source);
}
public string Serialize()
{
return JsonConvert.SerializeObject(
this, Formatting.Indented);
}
public override string ToString()
{
return this.Serialize();
}
public static TBaseType FromString(string json)
{
return JsonConvert.DeserializeObject<TBaseType>(json);
}
}
It is possible to return one or many primitive, complex, or entity types from a service operation.
A primitive type is what you'd expect: string, int, bool, etc.
A complex type is a class that doesn't have a unique key (a property named ID or the [DataServiceKey("<yourkeyhere>")] attribute)
An entity type is a class that does have a unique key
For instance:
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Scratch.Web
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ScratchService : DataService<ScratchContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
}
[WebGet]
public string GetPrimitive()
{
return "Success";
}
[WebGet]
public IQueryable<string> GetPrimitives()
{
return new[] { "Success", "Hello World" }.AsQueryable();
}
[WebGet]
public ComplexType GetComplexType()
{
return new ComplexType { Property1 = "Success", Property2 = "Hello World" };
}
[WebGet]
public IQueryable<ComplexType> GetComplexTypes()
{
return new[] {
new ComplexType { Property1 = "Success", Property2 = "Hello World" },
new ComplexType { Property1 = "Success", Property2 = "Hello World" }
}.AsQueryable();
}
[WebGet]
public EntityType GetEntityType()
{
return new EntityType { Property1 = "Success", Property2 = "Hello World" };
}
[WebGet]
public IQueryable<EntityType> GetEntityTypes()
{
return new[] {
new EntityType { Property1 = "Success1", Property2 = "Hello World" },
new EntityType { Property1 = "Success2", Property2 = "Hello World" }
}.AsQueryable();
}
}
public class ScratchContext { }
public class ComplexType
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
[DataServiceKey("Property1")]
public class EntityType
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
}
Perhaps you're running into some other problem?