MobileServiceClient with different Model name than table name - c#

Is there a way in Xamarin using MobileServiceClient to add an attribute to the class name to have a different table name?
i.e
this._client = new MobileServiceClient("myurl");
this._blogTable = _client.GetTable<Blog>();
But the table on the server is XCHX_Blogs
I would like to have my model class something like this
[TableName("XCHX_Blogs")]
public class Blog {
...
}
I cant seem to find a way to do this mapping in Xamarin forms (in the model).

In order to do exactly what you are asking you'd have to pull the Mobile Service Client SDK source into your app (instead of using the Nuget) so that you could use the internal MobileServiceTable<T> constructor directly:
this._blogTable = new MobileServiceTable<Blog>("XCHX_Blogs", this._client);
Alternatively you can use the non-generic MobileServiceTable, but then you'll have to handle the JSON de/serialization:
this._blogTable = _client.GetTable("XCHX_Blogs");
var blog = new Blog();
await this._blogTable.InsertAsync(JObject.FromObject(blog));

You can use DataContractAttribute or JsonContainerAttribute or DataTableAttribute
[DataContractAttribute(Name = "tableName")]
public class MyClass { ... }
IMobileServiceTable<MyClass> table = client.GetTable<MyClass>();
or
[JsonObjectAttribute(Title = "tableName")]
public class MyClass { ... }
IMobileServiceTable<MyClass> table = client.GetTable<MyClass>();
or
[DataTableAttribute("tableName")]
public class MyClass { ... }
IMobileServiceTable<MyClass> table = client.GetTable<MyClass>();
Personaly, I prefer the last solution because naming is coherent with type of objects.

Related

Load multiple bindings with Ninject

I am trying to load bindings in a class for a project. I am using 3rd party extensions for Caching and the class I need to load looks like below using c# and .net framework 472 .
public class CouchbaseCache : ICouchbaseCache, IDistributedCache
{
public CouchbaseCache(ICouchbaseCacheBucketProvider provider, IOptions<CouchbaseCacheOptions> options);
public IBucket Bucket { get; }
public CouchbaseCacheOptions Options { get; }
}
usually, If I have to load, I would use something like
Bind().To().InSingletonScope();
But how would I do it for the above class by giving the bucket info and Options as values while loading it? I could not get my head around it.
Also, ICouchbaseCachebucketProvider is an interface derived from INamedbucketProvider and derived class looks like
public interface INamedBucketProvider
{
string BucketName { get; }
IBucket GetBucket();
}
So far, I was able to get CouchbaseClientDefinition set up like this
Bind<ICouchbaseClientDefinition>().ToMethod(ctx =>
{
var options = new CouchbaseClientDefinition
{
Servers = new List<Uri>
{
new Uri("http://couchbase.com/")
}
};
return options;
}).InSingletonScope();
I need to give Uri for couchbase and also bucket name and the logic is all over the place. Any knowledge sharing will be greatly appreciated.
if the argument for the constructor of the CouchbaseCache is identical for the whole application life time then you can bind it with the use of binding with constructor arguments something like this where you are loading:
var options = new CouchbaseClientDefinition
{
Servers = new List<Uri>
{
new Uri("http://couchbase.com/")
}
};
var couchbaseCacheBucketProvider= new CouchbaseCacheBucketProvider
{
...
};
Bind<ICouchbaseClientDefinition().To<CouchbaseCache >()
.WithConstructorArgument(couchbaseCacheBucketProvider, options);
but you have to provide the couchbaseCacheBucketProvider.
if the arguments are different but they are limited for example if you have two version of the arguments you can use the named binding like this
var options1 = new CouchbaseClientDefinition
{
...
};
var options2 = new CouchbaseClientDefinition
{
...
};
var couchbaseCacheBucketProvider1= new CouchbaseCacheBucketProvider
{
...
};
var couchbaseCacheBucketProvider2= new CouchbaseCacheBucketProvider
{
...
};
Bind < ICouchbaseClientDefinition().To<CouchbaseCache>().WithConstructorArgument(couchbaseCacheBucketProvider, options1).Named("FirstBinding");
Bind < ICouchbaseClientDefinition().To<CouchbaseCache>().WithConstructorArgument(couchbaseCacheBucketProvider, options2).Named("SecondBinding");
However another Alternative is to use the FactoryPattern/Singleton to create your CouchbaseCache object. Then you need just to inject the Factory Class that you created and you can use the Factory Class to get the required CouchbaseCache object whenever it is required.

Returning a List or IEnumerable with IHttpActionResult [duplicate]

I am working with ASP.NET MVC 5 Web Api. I want consult all my users.
I wrote api/users and I receive this:
"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'"
In WebApiConfig, already I added these lines:
HttpConfiguration config = new HttpConfiguration();
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
But it still doesn't work.
My function for return data is this:
public IEnumerable<User> GetAll()
{
using (Database db = new Database())
{
return db.Users.ToList();
}
}
If you are working with EF, besides adding the code below on Global.asax
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
Dont`t forget to import
using System.Data.Entity;
Then you can return your own EF Models
Simple as that!
When it comes to returning data back to the consumer from Web Api (or any other web service for that matter), I highly recommend not passing back entities that come from a database. It is much more reliable and maintainable to use Models in which you have control of what the data looks like and not the database. That way you don't have to mess around with the formatters so much in the WebApiConfig. You can just create a UserModel that has child Models as properties and get rid of the reference loops in the return objects. That makes the serializer much happier.
Also, it isn't necessary to remove formatters or supported media types typically if you are just specifying the "Accepts" header in the request. Playing around with that stuff can sometimes make things more confusing.
Example:
public class UserModel {
public string Name {get;set;}
public string Age {get;set;}
// Other properties here that do not reference another UserModel class.
}
Given right answer is one way to go, however it is an overkill when you can fix it by one config settings.
Better to use it in the dbcontext constructor
public DbContext() // dbcontext constructor
: base("name=ConnectionStringNameFromWebConfig")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
Asp.Net Web API Error: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'
Add this code to global.asax below on Application_Start:
Update from .Ignore to .Serialize . It must work.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
public class UserController : ApiController
{
Database db = new Database();
// construction
public UserController()
{
// Add the following code
// problem will be solved
db.Configuration.ProxyCreationEnabled = false;
}
public IEnumerable<User> GetAll()
{
return db.Users.ToList();
}
}
I resolved it using this code to WebApiConfig.cs file
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
I don't like this code:
foreach(var user in db.Users)
As an alternative, one might do something like this, which worked for me:
var listOfUsers = db.Users.Select(r => new UserModel
{
userModel.FirstName = r.FirstName;
userModel.LastName = r.LastName;
});
return listOfUsers.ToList();
However, I ended up using Lucas Roselli's solution.
Update: Simplified by returning an anonymous object:
var listOfUsers = db.Users.Select(r => new
{
FirstName = r.FirstName;
LastName = r.LastName;
});
return listOfUsers.ToList();
Adding this in your Application_Start() method of Global.asax file should solve the problem
protected void Application_Start()
{
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
// ...
}
METHOD 2: [Not recommended]
If you are working with EntityFramework, you can disable proxy in your DbContext class constructor. NOTE: this code wll be removed if you update the model
public class MyDbContext : DbContext
{
public MyDbContext()
{
this.Configuration.ProxyCreationEnabled = false;
}
}
There's also this scenario that generate same error:
In case of the return being a List<dynamic> to web api method
Example:
public HttpResponseMessage Get()
{
var item = new List<dynamic> { new TestClass { Name = "Ale", Age = 30 } };
return Request.CreateResponse(HttpStatusCode.OK, item);
}
public class TestClass
{
public string Name { get; set; }
public int Age { get; set; }
}
So, for this scenario use the [KnownTypeAttribute] in the return class (all of them) like this:
[KnownTypeAttribute(typeof(TestClass))]
public class TestClass
{
public string Name { get; set; }
public int Age { get; set; }
}
This works for me!
My personal favorite: Just add the code below to App_Start/WebApiConfig.cs. This will return json instead of XML by default and also prevent the error you had. No need to edit Global.asax to remove XmlFormatter etc.
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Just put following lines in global.asax:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
Import
using System.Data.Entity;
Use AutoMapper...
public IEnumerable<User> GetAll()
{
using (Database db = new Database())
{
var users = AutoMapper.Mapper.DynamicMap<List<User>>(db.Users);
return users;
}
}
Use the following namespace:
using System.Web.OData;
Instead of :
using System.Web.Http.OData;
It worked for me
Add the below line
this.Configuration.ProxyCreationEnabled = false;
Two way to use ProxyCreationEnabled as false.
Add it inside of DBContext Constructor
public ProductEntities() : base("name=ProductEntities")
{
this.Configuration.ProxyCreationEnabled = false;
}
OR
Add the line inside of Get method
public IEnumerable<Brand_Details> Get()
{
using (ProductEntities obj = new ProductEntities())
{
this.Configuration.ProxyCreationEnabled = false;
return obj.Brand_Details.ToList();
}
}
Use [Serializable] for class:
Example:
[Serializable]
public class UserModel {
public string Name {get;set;}
public string Age {get;set;}
}
It worked for me!
Solution that worked for me:
Use [DataContract] for class and [DataMember] attributes for each property to serialize. This is enough to get Json result (for ex. from fiddler).
To get xml serialization write in Global.asax this code:
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
Read this article, it helped me to understand serialization:
https://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization
To add to jensendp's answer:
I would pass the entity to a user created model and use the values from that entity to set the values in your newly created model. For example:
public class UserInformation {
public string Name { get; set; }
public int Age { get; set; }
public UserInformation(UserEntity user) {
this.Name = user.name;
this.Age = user.age;
}
}
Then change your return type to: IEnumerable<UserInformation>
While all these answers above are correct, one may want to check the InnerException > ExceptionMessage.
If it says something like this "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.". This could be an issue because of default behavior of the EF.
By assigning LazyLoadingEnabled = false in your DbContext constructor will do the trick.
public class MyDbContext : DbContext
{
public MyDbContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
For more detailed reading about EagerLoading and LazyLoading behavior of EF refer this MSDN Article.
In my case I have had similar error message:
The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/xml; charset=utf-8'.
But when I dig deeper in it, the issue was:
Type 'name.SomeSubRootType'
with data contract name
'SomeSubRootType://schemas.datacontract.org/2004/07/WhatEverService'
is not expected. Consider using a DataContractResolver if you are
using DataContractSerializer or add any types not known statically to
the list of known types - for example, by using the KnownTypeAttribute
attribute or by adding them to the list of known types passed to the
serializer.
The way I solved by adding KnownType.
[KnownType(typeof(SomeSubRootType))]
public partial class SomeRootStructureType
This was solved inspired from this answer.
Reference: https://msdn.microsoft.com/en-us/library/ms730167(v=vs.100).aspx
I basically add one line which they are
entities.Configuration.ProxyCreationEnabled = false;
to UsersController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using UserDataAccess;
namespace SBPMS.Controllers
{
public class UsersController : ApiController
{
public IEnumerable<User> Get() {
using (SBPMSystemEntities entities = new SBPMSystemEntities()) {
entities.Configuration.ProxyCreationEnabled = false;
return entities.Users.ToList();
}
}
public User Get(int id) {
using (SBPMSystemEntities entities = new SBPMSystemEntities()) {
entities.Configuration.ProxyCreationEnabled = false;
return entities.Users.FirstOrDefault(e => e.user_ID == id);
}
}
}
}
You will have to define Serializer Formatter within WebApiConfig.cs available in App_Start Folder like
Adding config.Formatters.Remove(config.Formatters.XmlFormatter);
// which will provide you data in JSON Format
Adding config.Formatters.Remove(config.Formatters.JsonFormatter);
// which will provide you data in XML Format
Another case where I received this error was when my database query returned a null value but my user/view model type was set as non-nullable. For example, changing my UserModel field from int to int? resolved.
This also happens when the Response-Type is not public!
I returned an internal class as I used Visual Studio to generate me the type.
internal class --> public class
Visual Studio 2017 or 2019 is totally unthoughtful on this, because Visual Studio itself requires the output to be in json format, while Visual Studio's default format is "XmlFormat" (config.Formatters.XmlFormatter).
Visual Studio should do this automatically instead of giving developers so much trouble.
To correct this problem, go to the WebApiConfig.cs file, and add
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
after "config.MapHttpAttributeRoutes();" in the Register(HttpConfiguration config) method. This would allow your project to produce json output.
In my case I solved recreating the database.
I made some changes in a model and launching Update-Database in Package Manager Console I got the following Error:
"The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Activities_dbo.Projects_ProjectId". The conflict occurred in database "TrackEmAllContext-20190530144302", table "dbo.Projects", column 'Id'."
In case: If adding code to WebApiConfig.cs or Global.asax.cs doesn't work for you:
.ToList();
Add .ToList() function.
I tried out every solution but following worked for me:
var allShops = context.shops.Where(s => s.city_id == id)**.ToList()**;
return allShops;
I hope, it helps.
in my case, it was fixed when I removed the virtual keyword before my navigation properties,
I mean the reference tables.
so I changed
public virtual MembershipType MembershipType { get; set; }
to:
public MembershipType MembershipType { get; set; }

How to set custom templateBase as base template

I made custom template using TemplateBase. How to set my template as razor base template. I managed to do this using old api but than I had problem with caching. In new api caching seems much easier but I can't find any example of setting own template as base template.
In your start up routine or similar, add the following
var templateConfig = new TemplateServiceConfiguration
{
BaseTemplateType = typeof(YourCustomTemplateBase<>)
};
var service = RazorEngineService.Create(templateConfig);
Engine.Razor = service;
Add your template base should be created as
public abstract class YourCustomTemplateBase<T> : TemplateBase<T>
{
public string CustomString { get; set; }
}

Under what conditions does RavenDB store variables of an instance of a class?

I read on this tutorial that RavenDB can be used to store instances of a class (such as the Menu object they use). I tried reproducing their example, but used a more minimal example, in C#:
using Raven.Client.Document;
using Raven.Client;
namespace Project3
{
class MainClass
{
public static void Main()
{
IDocumentStore docStore = new DocumentStore()
{
Url = "http://localhost:8080",
DefaultDatabase = "Northwind"
};
docStore.Initialize();
var session = docStore.OpenSession();
StringHolder strHolder = new StringHolder();
session.Store(strHolder);
session.SaveChanges();
}
}
class StringHolder
{
string name = "kj";
}
}
However, when I run this and check the database, this is what I see logged:
So the StringHolder parameter name isn't being stored. Why does this occur, when in the tutorial the analogous process with Menu and Allergenics causes the class variables to be stored in the resulting document?
The property name of class StringHolder is private, so it does not get serialized. Only public properties are saved to the database.

dealing with dynamic properties on oData client

I have the following class on both server and client
public class Entity
{
public string Id {get; set;}
public string Name {get; set;}
public Dictionary<string, object> DynamicProperties {get; set;}
}
As far as I have seen all the examples of open type describes about having dynamic properties on the server side, but the properties on the client needs to be explicitly declared.When I send a POST request from the client how do i send the dynamic properties ?. I can't declare all the dynamic properties on the client side. There are numerous properties and each object will contain different set of dynamic properties in the client side. These dynamic properties are stored in the DynamicProperties dictionary in the client side. How do I send the object of above entity class to the server side, so that server will interpret the contents of DynamicProperties dictionary as dynamic properties ?. Any help is appreciated.
===========================Follow-up for sam's answer=======================
static void Main(string[] args1)
{
container.Customers.ToList();
Customer newCustomer = new Customer();
newCustomer.Id = 19;
newCustomer.Properties = new Dictionary<string, object>
{
{"IntProp", 9},
{"DateTimeOffsetProp", new DateTimeOffset(2015, 7, 16, 1, 2, 3, 4, TimeSpan.Zero)},
{"blah","ha"}
};
try
{
addCustomer(newCustomer);
container.AddToCustomers(newCustomer);
container.SaveChanges();
}
catch (Exception)
{
}
Customer newCustomer1 = new Customer();
newCustomer1.Id = 20;
newCustomer1.Properties = new Dictionary<string, object>
{
{"IntProp", 10},
{"dir","north"}
};
addCustomer(newCustomer1);
container.AddToCustomers(newCustomer1);
container.SaveChanges();
newCustomer1.Properties["dir"] = "south";
container.UpdateObject(newCustomer1);
container.SaveChanges();
Console.ReadKey();
}
private static void addCustomer(Customer customer)
{
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
foreach (var property in customer.Properties)
{
args.Entry.AddProperties(new ODataProperty
{
Name = property.Key,
Value = property.Value // for enum, complex type, should to create ODataEnumValue and ODataComplexValue.
});
}
});
}
I am getting an error stating Multiple properties with the name 'IntProp' were detected in an entry or a complex value. In OData, duplicate property names are not allowed. Also, I doubt if creating an action each time before sending an object like how I am doing now is a valid approach as I get lot of objects from a source and I send it to the server. If I create an action for each object then it might blow up the memory as oData client holds these actions in memory. How do I handle my scenario ?. Kindly help me.
Also, one more question if I comment the container.Customers.ToList() it fails stating that I am trying to add undeclared properties. Why is that ?
If you are using OData Client Code Generator, you can use the partial class to define/retrieve/save the dyanmic properties.
For example, in your client side, you can define a partial class for your Entity
public partial class Entity
{
// Dynamic property "Email"
[global::Microsoft.OData.Client.OriginalNameAttribute("Email")]
public string Email
{
get
{
return this._Email;
}
set
{
this.OnEmailChanging(value);
this._Email = value;
this.OnEmailChanged();
this.OnPropertyChanged("Email");
}
}
private string _Email;
partial void OnEmailChanging(string value);
partial void OnEmailChanged();
}
Then, you can use this to insert/retrieve/save the dynamic property "Email".
You can do like this:
Container container = new Container(new Uri("http://..."));
Entity entity = new Entity();
...
entity.Email = "xxxx";
container.AddToEntities(entity);
container.SaveChanges();
For similar implementation, you can refer to my sample project.
========== iteration 2 ================
For client Entity class with IDictionary<string,object>, I think the hook is what you're looking for.
For example, on client side:
public partial class Entity
{
public IDictionary<string, object> Properties { get; set; }
.....
}
It should work if you insert the following codes before
container.AddToEntities(entity);
For example:
Entity entity = new Entity();
...
entity.Properties = new Dictionary<string, object>
{
{"IntProp", 9},
{"DateTimeOffsetProp", new DateTimeOffset(2015, 7, 16, 1, 2, 3, 4, TimeSpan.Zero)}
};
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
foreach (var property in entity.Properties)
{
args.Entry.AddProperties(new ODataProperty
{
Name = property.Key,
Value = property.Value
});
}
});
container.AddToEntities(entity);
container.SaveChanges();
Where, AddProperties is an extension method. You can find it in my sample project
and the latest commit
Besides, the hood method only works with OData Client V6.12 or above.
Hope it can help you.
========== iteration 3 ================
First, you call the following method,
container.Configurations.RequestPipeline.OnEntryStarting(...);
It means to add an action which will be called in later execution. In your codes, you call it twice, So, there are two actions added. These two actions will be called one by one when execute to save your newCustomer1
That's, newCustomer1 will have newCustomer's dynamic properties (action 1), meanwhile, it will have its own dynamic properties (action 2). That's why you got the duplicate property name exception.
To resolve it, you can just to renew a Container. See my project's update.
For container.Customers.ToList(), it seems an OData client issue.
[Answering my own question : Another approach]
Extending Sam Xu's approach for iteration 2. We can do it as below. (For the sake of clarity let's assume the name of the class in question as Book)
public partial class Book
{
public string ISBN {get; set;}
public IDictionary<string, object> DynamicProperties { get; set; }
}
// This portion can be put in a function and can be invoked only once
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
if(args.Entity.GetType() == typeof(Book))
{
var book = args.Entity as Book
foreach (var property in book.DynamicProperties)
{
args.Entry.AddProperties(new ODataProperty
{
Name = property.Key,
Value = property.Value
});
}
}
});
AddProperties extension method implementation is provided in Sam Xu's implementation

Categories