I am sitting playing with elastic search from C#, and I wanted to create a query using an anonymous type in C# serialized to JSON. But I ran in to a problem as I need JSON that looks like this in one part:
{"bool": {<unimportant for question>}}
This would translate into a c# class that has a field named bool. Is this possible? (My guess is no...)
I think I will need custom serialization, or maybe elastic search provides some other alternative name for bool.
If you want to name variables the same as keywords you can prefix them with #.
bool #bool = false;
I would avoid doing this in ALL circumstances where possible. It's just plain confusing.
You can set the name in a [DataMember] attribute, but you need to use real classes (not anonymous).
using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
// You must apply a DataContractAttribute or SerializableAttribute
// to a class to have it serialized by the DataContractSerializer.
[DataContract()]
class Enterprise : IExtensibleDataObject
{
[DataMember(Name = "bool")]
public bool CaptainKirk {get; set;}
// more stuff here
}
More Info: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute.aspx
Use the DateMember attribute to specify what the serialised name is:
[DataMember(Name = "bool")]
public string MyBoolean { get; set; }
See also: JavaScriptSerializer.Deserialize - how to change field names
Related
Hello all and everyone!
English is not my native language. I apologize for any errors.
I decided to use the AttributeProviderAttribute to reduce repetitions in the code. But I don’t understand how to check: does attribute redirection work or not? And how are contradictions between their own attributes and redirected attributes handled?
//using namespaces
using System.ComponentModel;
using System.Reflection;
//Test Classes Foo, Bar:
public class Foo {
[DisplayName(nameof(Astring) + "Name")]
public string Astring { get; set; }
}
public class Bar {
[AttributeProvider(nameof(Foo), nameof(Foo.Astring))]
public string Bstring { get; set; }
}
// Code for checking attributes:
PropertyInfo bStrProp = typeof(Bar).GetProperty(nameof(Bar.Bstring));
Questions:
The debugger does not display a DisplayNameAttribute for Bar.Bstring. How do I know if attribute redirection worked?
How are contradictions between own attributes and redirected from another property handled?
a. Priority own attributes.
b. Priority imported attributes.
c. Priority last attributes.
d. An exception is generated.
Meta data analyzing code must explicitly support AttributeProviderAttribute to be usefully assigned to a property.
I am having a hard time finding good detail on NEST 2.0, the wrapper for Elasticsearch 2.2 I am using. My question is this: Can I do a bulk insert on an object (class with public data members) and map that to Elasticsearch where only the mapped fields between my C# class and the ES server mapping will save? And it will not add the additional fields in my class I do not want?
Right now I have a class of with strings and doubles and lists of other classes in it. I want to save the strings and doubles, but NOT include the Lists on my bulk inserts to Elasticsearch. It wants to save every piece of data in every field of my class. Is there a class member attribute or some other way to say "do not add this field if it has no mapping" that I have missed? I hope so.
You can ignore properties of your POCO in a number of ways with NEST 2.x. Let's use the following POCO as an example
using Nest;
using Newtonsoft.Json;
[ElasticsearchType(Name = "company")]
public class Company
{
public string Name { get; set; }
[String(Ignore = true)]
public string IgnoreViaAttribute { get; set; }
public string IgnoreViaSettings { get;set; }
[JsonIgnore]
public string IgnoreViaSerializerSpecificAttribute { get; set; }
}
1.Using the Ignore property on a derived ElasticsearchPropertyAttribute type (in our example, StringAttribute on IgnoreViaAttribute property) applied to the property that should be ignored on the POCO
2.Using the .InferMappingFor<TDocument>(Func<ClrTypeMappingDescriptor<TDocument>, IClrTypeMapping<TDocument>> selector) on the connection settings
var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
.InferMappingFor<Company>(i => i
.Ignore(p => p.IgnoreViaSettings)
);
var client = new ElasticClient(settings);
These settings are cached per instance of ConnectionSettings.
3.Using an ignore attribute applied to the POCO property that is understood by the IElasticsearchSerializer used, and inspected inside of the CreatePropertyMapping() on the serializer. In the case of the default JsonNetSerializer, this is the Json.NET JsonIgnoreAttribute. In our example, this is demonstrated by the attribute applied to the IgnoreViaSerializerSpecificAttribute property.
What I found by digging around a bit and testing a small class is that the following structure did indeed hide the attributes when you post a class with NEST 2.0 C#. If you do this just above the class member you wish to ignore when doing a bulk add that covers it.
[String(Ignore = true)]
I'm preparing an Entity Framework model (CODE FIRST) for my C#.NET project. It dawned on me that I was going to have PageTitles stored as strings which have no length restrictions apart from the max and minimum bits available.
I have assumed that if I know a string will be 255 characters long and never exceed that, I could declare my string as a new char[255].
What are the downsides of using char instead of string.
What are the upsides of using char instead of string.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ContentManagementSystem.Models
{
public class Page
{
int Id { get; set; }
string PageTitle { get; set; }
// This seems wasteful and unclear
char[] PageTitle = new char[255];
// How would i apply { get; set; } to this?
}
}
Is there some way of restricting a strings size?
---------------ANSWERED---------------------
This is now my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace ContentManagementSystem.Models
{
public class Page
{
public int Id { get; set; }
[MaxLength(255)] public string Title { get; set; }
[MaxLength(255)] public string Description { get; set; }
public string Content { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<Page> Pages { get; set; }
}
}
No, you should not use a char[] when you intend to operate on it as a string. Why? Beacuse string has a ton of useful methods that will be unavailable to you if you use a character array. Performance benefits of a character array, if any, would be exceedingly minimal.
EDIT: As DamienG pointed out, this will only work in case of code first.
Are you looking for this?
[MaxLength(255)]
public string PageTitle { get; set; }
Referenced dll:
Assembly System.ComponentModel.DataAnnotations.dll
Referenced namespace:
namespace System.ComponentModel.DataAnnotations
I wouldn't store strings as chars as you'll be forever cursing as you pass them around to things that want a string.
You can specify a maximum length for a string in Entity Framework using the designer for model-first or using the MaxLength attribute on the property for Code First models.
Use the StringLength attribute to inform the framework about the maximum length. You can continue to use strings instead of character arrays.
using System.ComponentModel.DataAnnotations;
...
[StringLength(255)]
public string PageTitle { get; set; }
Using the StringLength attribute in this case may be preferable to the MaxLength attribute because StringLength can also used by the model validation framework to validate user input.
If basic inconvenience is note enough to convince you not to do so - it is also against API design guidelines for C#/.Net - returning arrays via get/set methods is not recommended due to unclear behavior (is it copy/reference) and potential performance impact due to copying large arrays.
When you re-read your sample code you will already know the answer - it is bad idea to replace string with char[255] in public API because it will be very hard to deal with - you don't know how to set it. Most people will expect "XxxxxTitle" property to be be of any type string.
If you need to put length restriction - just enforce it in set method.
I'm developing a desktop application with .NET. I'd like to save some data into a file in a way that would later give me some degree of freedom in changing the data I'm saving, such as adding new fields, while retaining the possibility to read saves from older formats.
This answer recommends to use DataContractSerializer instead of BinaryFormatter.
However I can't use the [DataContract] attribute on my classes in the project. After using System.Runtime.Serialization; I still get errors about unknown types.
The project targets .NET Framework 4.
I've learned that Data Contracts are part of the WCF framework, I assume I should somehow configure my project to use it. How?
In C# namespaces can be shared across multiple assemblies. You have to add a reference to System.Runtime.Serialization.dll, which contains [DataContract] attribute.
probably you are missing to specify the Know Type attribute when it is needed
Have a look at the below example:
public interface ICustomerInfo
{
string ReturnCustomerName();
}
[DataContract(Name = "Customer")]
public class CustomerTypeA : ICustomerInfo
{
public string ReturnCustomerName()
{
return "no name";
}
}
[DataContract(Name = "Customer")]
public class CustomerTypeB : ICustomerInfo
{
public string ReturnCustomerName()
{
return "no name";
}
}
[DataContract]
[KnownType(typeof(CustomerTypeB))]
public class PurchaseOrder
{
[DataMember]
ICustomerInfo buyer;
[DataMember]
int amount;
}
you have to specify the type of ICustomerInfo otherwise the serialization engine cannot guess the type
Just add wcf service template to your application and declare your function and data members their and reference wcf in your project.
I was trying to implement parsing a JSON response as shown here for my Windows Phone 7 project in C#. But I am stuck with a compilation error as "The type or namespace name 'Serializable' could not be found (are you missing a using directive or an assembly reference?)"
I have the imports using System.Runtime.Serialization;
using System.Runtime.Serialization.Json; I am not sure what are import I am missing. I tried to include using System.ServiceModel.Web; But the Web part is not recognized.
I thought my project is not pointing to the right framework from here. But in the Assembly information, there is no option for me to change the target framework.
This looks like a similar problem to mine, but I couldn't find the JSON.NET in .net dlls which is filtered for Windows Phone.
Can someone help me to get this JSON thing working for Windows Phone 7.
Thank in Advance.
EDIT - 7/3/11
My Jason response is
{ "serviceresponse" : { "servicename" : "RequestRegisterUser", .....
And my Response objects are:
[DataContract]
public class serviceresponse
{
[DataMember]
public String servicename { get; set; }
.
.
.
And my Deserialize method:
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
obj = (T)serializer.ReadObject(stream);
return obj;
}
}
Now I am getting this error after Deserializing the response:
servicename Could not evaluate expression string
( I could not import System.ServiceModel.Web though I have the dll in the reference. A compilation error on the .Web part (The type or namespace name 'Web' does not exist in the namespace 'System.ServiceModel') )
EDIT After more research, I found my response when viewed in the debugger is actually
{
\"serviceresponse\": {
\"servicename\": \"RequestRegisterUser\",.....
I searched for this and found this could be a problem. How can I format it to correct JSON String??
You need to add a reference to both System.Runtime.Serialization and System.ServiceModel.Web assemblies. The DataContractJsonSerializer is defined in System.ServiceModel.Web assembly in the Silverlight version of the framework, that's why you need the extra assembly reference.
And by the way JSON.NET is a a popular open-source JSON framework for .Net and you could find more about it here. It's not part of the .Net framework, that's why you can't find it.
Edit:
About the compilation, in Silverlight the DataContractJsonSerializer is in the System.Runtime.Serialization.Json namespace, but in the assembly System.ServiceModel.Web (in System.ServiceModel.Web.dll), which is a bit confusing. So you use it like this - System.Runtime.Serialization.Json.DataContractJsonSerializer, but need the extra assembly reference. You also need to reference the System.Runtime.Serialization assembly as well, because that is where the DataContract attribute is defined. I see you have already successfully compiled the code, but I hope the extra explanation makes it more clear for future readers.
About the serialization itself - as you have already found out, you will need two objects, simply because that's the structure of the json. However, the DataContract and DataMember attributes have a Name property that you can use instead of changing the name of the fields. Also, you can use properties instead of fields if you like.
For example:
[DataContract]
public class ServiceResponse
{
[DataMember(Name = "servicename")]
public string ServiceName { get; set; }
}
[DataContract]
class Response
{
[DataMember(Name = "serviceresponse")]
public ServiceResponse ServiceResponse { get; set; }
}
And one last thing - you don't need the call to Activator.CreateInstance(); in your Deserialise method.
It certainly would help if you posted your code. So I can only guess:
I assume you have something like this:
[Serializable]
public class Response
{
[DataMember]
public string name { get; set; }
...
}
But that's a mix-up of two serialization concepts, one of which is not supported in Phone 7. The correct attributes are DataContract and DataMember:
[DataContract]
public class Response
{
[DataMember]
public string name { get; set; }
...
}
I found the issue. Though my class name is "serviceresponse", I used another wrapper class as
public class Response
{
public serviceresponse serviceres;//Don't Do this....
}
where I used the variable name for serviceresponse as serviceres. But when I changed it to " serviceresponse" its all working.
public class Response
{
public serviceresponse serviceresponse;//This fixed it.
}