I have a WCF operation MyGetVersion() that returns a System.Version. When debugging a call to it from a Silverlight service reference, I verified that the service returns the correct System.Version object. In the service reference, the auto-generated method:
public System.Version EndMyGetVersion(System.IAsyncResult result) {
object[] _args = new object[0];
System.Version _result = ((System.Version)(base.EndInvoke("MyGetVersion", _args, result)));
return _result;
}
raises the exception:
Attempt by method 'DynamicClass.ReadVersionFromXml(System.Runtime.Serialization.XmlReaderDelegator, System.Runtime.Serialization.XmlObjectSerializerReadContext, System.Xml.XmlDictionaryString[], System.Xml.XmlDictionaryString[])' to access method 'System.Version..ctor()' failed.
I had to turn on the "break on CLR exception" helper to see this. Otherwise, it is a TargetInvocationException. The System.Version() constructor is public as far as I can tell. What am I doing wrong?
The problem is that the constructor of System.Version is public in the .NET Framework, but it's not in Silverlight (it's internal, according to Reflector). So while the type is serializable in the full framework, it's not in Silverlight, and the Add Service Reference tool should have replaced it with an equivalent type in SL - this is a bug in the tool (I'll report it to the product team, thanks for finding it).
As workarounds, I'd suggest to use a "surrogate" type for Version, and use it in your service contract for data transfer only:
[DataContract]
public class VersionDTO
{
[DataMember]
public int Major { get; set; }
[DataMember]
public int Minor { get; set; }
[DataMember]
public int Build { get; set; }
[DataMember]
public int Revision { get; set; }
public VersionDTO(Version version) {
this.Major = version.Major;
this.Minor = version.Minor;
this.Build = version.Build;
this.Revision = version.Revision;
}
}
[ServiceContract]
public interface ITest
{
[OperationContract]
VersionDTO GetVersion();
}
Another option, given the issue you mentioned in the comment, would be to replace the reference to the Version class in the generated proxy for Silverlight with a class which is equivalent to it. The class below can be used to deserialize a Version object in SL from .NET.
[DataContract(Name = "Version", Namespace = "http://schemas.datacontract.org/2004/07/System")]
public class SLVersion
{
[DataMember(Order = 1, Name = "_Build")]
public int Build { get; set; }
[DataMember(Order = 2, Name = "_Major")]
public int Major { get; set; }
[DataMember(Order = 3, Name = "_Minor")]
public int Minor { get; set; }
[DataMember(Order = 4, Name = "_Revision")]
public int Revision { get; set; }
}
Related
I have a WCF service with this function :
namespace PortfolioSerivce
{
[ServiceContract]
public interface IService1
{
[OperationContract]
bool CreateOrders(List<OrderDTO> ListOrder);
}
}
and here its code
public bool CreateOrders(List<OrderDTO> ListOrder)
{
return true;
}
The class OrderDTO is defined as below :
[DataContract]
public class OrderDTO
{
[DataMember]
public int Id { get; set; }
[DataMember]
public char OrderType { get; set; }
[DataMember]
public float OrderedQty { get; set; }
[DataMember]
public float PreUNitCost { get; set; }
[DataMember]
public float PostUnitCost { get; set; }
[DataMember]
public float MarketPrice { get; set; }
[DataMember]
public float ClientId { get; set; }
[DataMember]
public float SecurityId { get; set; }
}
In WPF, I have a function in which I want to pass a list to the WCF function:
internal bool RemoteCreateOrders(List<Position> securityMarketDTO)
{
List<OrderDTO> ListOrders = new List<OrderDTO>();
Tools.MyRemoteService.CreateOrders((List<OrderDTO>)ListOrders);
return true;
}
When I compile I got those errors :
The best overloaded method match for 'PortfolioView.PortfolioService.Service1Client.CreateOrders(PortfolioView.PortfolioService.OrderDTO[])' has some invalid arguments
Cannot convert from 'System.Collections.Generic.List' to 'PortfolioView.PortfolioService.OrderDTO[]'
What is the problem here, as I send a list of OrderDTO from my app and in WCF I declared as parameter a list of OrderDTO. What conversion should I use?
Thanks in advance.
From you exception , you Service1Client's method CreateOrders needs a variable of type OrderDTO[], while you pass List.
Please pass the variable of right type , use ListOrders.ToArray to convert list to array.
Or if you want to pass List, please let vs generate List for collection when you add service reference.
When adding service reference using vs, you could click advanced at the bottom, and then your could configure Collection type.
I am using CreateDatabaseIfNotExists when creating a database, but it just doesn't drop the database and then it starts initializing it.
There is my DbContext.
public class AppDbContext : DbContext
{
public AppDbContext() : base("Valtrends")
{
InitializeDbContext();
}
public DbSet<FactorType> FactorTypes { get; set; }
public DbSet<ComplexType> ComplexTypes { get; set; }
public DbSet<Value> Values { get; set; }
public DbSet<DataLoader.Entities.Version> Versions { get; set; }
public DbSet<DefaultPlotData> DefaultPlotData { get; set; }
public DbSet<GraphBucket> GraphBuckets { get; set; }
public DbSet<XfactorFrom> XfactorsFrom { get; set; }
public DbSet<XfactorTo> XfactorsTo { get; set; }
public DbSet<DistributionData> DistributionData { get; set; }
public DbSet<Bin> Bins { get; set; }
public DbSet<DefaultPlotSettings> DefaultPlotSettings { get; set; }
private void InitializeDbContext()
{
Database.SetInitializer(new AppDbInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<FactorType>().HasMany(m => m.CompatibilityListXY).WithMany();
}
}
}
And there is the the first part of my AppDbInitializer.
public class AppDbInitializer : CreateDatabaseIfNotExists<AppDbContext>//DropCreateDatabaseAlways<AppDbContext>
{
public override void InitializeDatabase(AppDbContext context)
{
base.InitializeDatabase(context);
var jsonImporter = new JsonImporter();
List<DataLoader.Entities.Version> versions = (jsonImporter.ImportFromJson<List<DataLoader.Entities.Version>>("Versions.json"));
context.Versions.AddRange(versions);
context.SaveChanges();
After SaveChanges I get a violation of primary keys exception on the entity version.
I am using CreateDatabaseIfNotExists when creating a database, but it just doesn't drop the database and then it starts initializing it
It never drops an existing database. As the name implies, it checks if database exists, and if yes, it does nothing, otherwise it creates and initializes it.
Also note that the InitializeDatabase method of the IDatabaseInitializer is always called, it's the class that implements it responsibility what actual action to perform.
In your case you incorrectly assume that the base method will always create the new database, which is not the case. If you want to add a code that executes only when a new database is created, then you should override the Seed method instead:
public class AppDbInitializer : CreateDatabaseIfNotExists<AppDbContext>
{
protected override void Seed(AppDbContext context)
{
var jsonImporter = new JsonImporter();
List<DataLoader.Entities.Version> versions = (jsonImporter.ImportFromJson<List<DataLoader.Entities.Version>>("Versions.json"));
context.Versions.AddRange(versions);
context.SaveChanges(); // you don't need this, it's automatically called after `Seed` call
}
}
This is one of the class definitions within a DLL I use in my WCF service.
[DataContract]
public class ScenarioXML
{
[DataMember(Order = 1)]
public long? TNRScenario { get; set; }
[DataMember(Order = 2)]
public long? TNRProject { get; set; }
[DataMember(Order = 3)]
public int? Priority { get; set; }
// ...
[DataMember(Order = 19)]
public List<ScenarioAssetXML> ScenarioAssets { get; set; }
[DataMember(Order = 20)]
public List<CalendarXML> Calendars { get; set; }
[DataMember(Order = 21)]
public ScenarioTriggerCollectionXML ScenarioTriggerCollection { get; set; }
}
I'm using DataContract instead of ProtoContract, so I can expose this class to a Silverlight project through a WSDL, and still use Protobuf-net for serialization.
Now, when I use the following code in my WCF service, the original "scenario" and the "restoredModel" are identical.
MemoryStream msTestString = new MemoryStream();
Serializer.Serialize<ScenarioXML>(msTestString, scenario);
string memento = Convert.ToBase64String(msTestString.ToArray());
byte[] byteAfter64 = Convert.FromBase64String(memento);
MemoryStream afterStream = new MemoryStream(byteAfter64);
ScenarioXML restoredModel = Serializer.Deserialize<ScenarioXML>(afterStream);
However, when I use the same code in Silverlight, the TNRScenario value is null.
Similarly, the TNRScenarioAsset property of the objects in the ScenarioAssets list are null.
[DataContract]
public class ScenarioAssetXML
{
[DataMember(Order = 1)]
public long? TNRScenarioAsset { get; set; }
[DataMember(Order = 2)]
public long? TNRScenario { get; set; }
[DataMember(Order = 3)]
public string Asset { get; set; }
[DataMember(Order = 4)]
public string Action { get; set; }
}
When I make the first property a string, it completely vanishes after (de)serialization. When I put a dummy bool as a first property, the bool is there, but the second property, in this case ScenarioAssets, is still null. There's something weird going on here...
Am I doing somethign wrong, or is this a bug?
Edit:
You're right Marc! The orders get messed up in the WSDL-generated code.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="ScenarioXML", Namespace="http://schemas.datacontract.org/2004/07/DataCollectionDLL")]
public partial class ScenarioXML : object, System.ComponentModel.INotifyPropertyChanged {
private System.Nullable<long> TNRScenarioField;
private System.Nullable<long> TNRProjectField;
private System.Nullable<int> PriorityField;
//...
[System.Runtime.Serialization.DataMemberAttribute()]
public System.Nullable<long> TNRScenario {
get {
return this.TNRScenarioField;
}
set {
if ((this.TNRScenarioField.Equals(value) != true)) {
this.TNRScenarioField = value;
this.RaisePropertyChanged("TNRScenario");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=1)]
public System.Nullable<long> TNRProject {
get {
return this.TNRProjectField;
}
set {
if ((this.TNRProjectField.Equals(value) != true)) {
this.TNRProjectField = value;
this.RaisePropertyChanged("TNRProject");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=2)]
public System.Nullable<int> Priority {
get {
return this.PriorityField;
}
set {
if ((this.PriorityField.Equals(value) != true)) {
this.PriorityField = value;
this.RaisePropertyChanged("Priority");
}
}
}
//...
However, I'm not sure how to correctly implement that partial class? I created it in the WCF service, but that seems to confuse the compiler. Getting the following errors:
Error 6 'DataCollectionDLL.ScenarioXML' does not contain a definition for 'TNRScenario' and no extension method 'TNRScenario' accepting a first argument of type 'DataCollectionDLL.ScenarioXML' could be found (are you missing a using directive or an assembly reference?)
Error 2 Cannot convert type 'DataCollectionDLL.ScenarioXML [c:\Projects\Flowcontrol 1.7.1.1\flowcontrolFC.Web\Libraries\DataCollectionDLL.dll]' to 'DataCollectionDLL.ScenarioXML [C:\Projects\Flowcontrol 1.7.1.1\flowcontrolFC.Web\DAL\DataCollectionClasses\ScenarioXML.cs(31)]'
Then tried it in the Silverlight project, which compiles fine but that doesn't solve the problem. Results are the same.
The partial class I created:
namespace DataCollectionDLL
{
[ProtoContract]
[ProtoPartialMember(1, "TNRScenario")]
[ProtoPartialMember(2, "TNRProject")]
[ProtoPartialMember(3, "Priority")]
//...
[ProtoPartialMember(21, "ScenarioTriggerCollection")]
partial class ScenarioXML
{
}
}
It sounds like you used WSDL-generated proxies; that can confuse things a little bit, because protobuf-net really really cares what the numbers are, and WSDL can sometimes play fast and loose with those. It would really help if I could see the WSDL-generated proxy classes (in the .designer.cs), but I'm going to assume this is the problem. Fortunately, most code-generators use partial class, so you can add your own partial class in a separate file to add extra information into the same type, in particular: more attributes. For example:
namespace The.Same.Namespace
{
[ProtoContract]
[ProtoPartialMember(1, "TNRScenario")]
[ProtoPartialMember(2, "TNRProject")]
// ...
[ProtoPartialMember(21, "ScenarioTriggerCollection")]
partial class ScenarioXML { }
}
This will get merged by the compiler into the ScenarioXML class, and should allow protobuf-net to use the correct numeric identifiers for each property.
I'm using the following technologies: WinForms, Entity Framework 4.4 (5.0 on .NET 4.0), DBContext
I have (what I think is) a very simple Master/Details form, that actually worked just fine before I upgraded from EF 4.0 to EF 4.4. Now, for some reason, the Details DataGridView simply doesn't populate with any data!
Here's my auto-generated schema code:
public partial class RoadMapping
{
public RoadMapping()
{
this.RoadCharacteristics = new HashSet<RoadCharacteristic>();
}
public int RoadMappingID { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual ICollection<RoadCharacteristic> RoadCharacteristics { get; set; }
}
public partial class RoadCharacteristic
{
public RoadCharacteristic()
{
}
public int RoadCharacteristicID { get; set; }
public int RoadMappingID { get; set; }
public string Value { get; set; }
public string Description { get; set; }
public virtual RoadMapping RoadMapping { get; set; }
}
Here's my code that was working with EF 4.0:
SATContext = new SafetyAssessmentToolEntities();
dataGridViewMappings.DataSource = bindingSourceMappings;
dataGridViewDetails.DataSource = bindingSourceDetails;
bindingSourceMappings.DataSource = SATContext.RoadMappings;
bindingSourceDetails.DataSource = bindingSourceMappings;
bindingSourceDetails.DataMember = "RoadCharacteristics";
Here's the code that isn't working with EF 4.4:
SATContext = new SafetyAssessmentToolEntities();
SATContext.RoadMappings.Load();
SATContext.RoadCharacteristics.Load();
dataGridViewMappings.DataSource = bindingSourceMappings;
dataGridViewDetails.DataSource = bindingSourceDetails;
bindingSourceMappings.DataSource = SATContext.RoadMappings.Local.ToBindingList();
bindingSourceDetails.DataSource = bindingSourceMappings;
bindingSourceDetails.DataMember = "RoadCharacteristics";
Please note that bindingSourceMappings and bindingSourceDetails are declared by the form designer.
I know there are a lot of more advanced and code-intensive ways to make this work, but I can't understand why this very simple way of doing it won't work anymore.
Any suggestions?
public partial class SafetyAssessmentToolEntities : DbContext
{
public SafetyAssessmentToolEntities()
: base("name=SafetyAssessmentToolEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<RoadCharacteristic> RoadCharacteristics { get; set; }
public DbSet<RoadMapping> RoadMappings { get; set; }
}
I am working on setting up a new project using Code First for entity framework 5 in silverlight using RIA services. I have created a test project due to some issues I have encountered and will post the code below.
Namely, I get an 'Object reference not set to an instance of an object' error anytime I attempt to build the silverlight client project which should generate the client proxy classes.
Just to be clear, this error is not while running or debugging the application, but when building it.
I have isolated that this only happens if I have any navigation properties/Foreign Keys defined on my Code First classes.
Any help tonight would be greatly appreciated.
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? BirthDate { get; set; }
public virtual List<Character> Characters { get; set; }
}
public class Character
{
public int CharacterId { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
public string CharacterName { get; set; }
}
public class CharacterDbContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Character> Characters { get; set; }
public CharacterDbContext()
{
if (HttpContext.Current == null)
{
Database.SetInitializer<CharacterDbContext>(null);
}
}
}
[EnableClientAccess]
public class CharacterDbService : DbDomainService<CharacterDbContext>
{
#region Basic Methods for Person with the context property of Persons
[Query]
public IQueryable<Person> GetPersons()
{
return DbContext.Persons;
}
[Insert]
public void InsertPerson(Person entity)
{
DbEntityEntry<Person> entityEntry = DbContext.Entry(entity);
if (entityEntry.State != EntityState.Detached)
{
entityEntry.State = EntityState.Added;
}
else
{
DbContext.Persons.Add(entity);
}
}
[Update]
public void UpdatePerson(Person entity)
{
DbContext.Persons.AttachAsModified(entity, ChangeSet.GetOriginal(entity), DbContext);
}
[Delete]
public void DeletePerson(Person entity)
{
DbEntityEntry<Person> entityEntry = DbContext.Entry(entity);
if (entityEntry.State != EntityState.Deleted)
{
entityEntry.State = EntityState.Deleted;
}
else
{
DbContext.Persons.Attach(entity);
DbContext.Persons.Remove(entity);
}
}
#endregion
#region Basic Methods for Character with the context property of Characters
[Query]
public IQueryable<Character> GetCharacters()
{
return DbContext.Characters;
}
[Insert]
public void InsertCharacter(Character entity)
{
DbEntityEntry<Character> entityEntry = DbContext.Entry(entity);
if (entityEntry.State != EntityState.Detached)
{
entityEntry.State = EntityState.Added;
}
else
{
DbContext.Characters.Add(entity);
}
}
[Update]
public void UpdateCharacter(Character entity)
{
DbContext.Characters.AttachAsModified(entity, ChangeSet.GetOriginal(entity), DbContext);
}
[Delete]
public void DeleteCharacter(Character entity)
{
DbEntityEntry<Character> entityEntry = DbContext.Entry(entity);
if (entityEntry.State != EntityState.Deleted)
{
entityEntry.State = EntityState.Deleted;
}
else
{
DbContext.Characters.Attach(entity);
DbContext.Characters.Remove(entity);
}
}
#endregion
}
Your foreign key fields aren't mapped, thus they can't be interpreted by the proxy code generator (the piece of code called to build your proxy during compilation).
You should put in you DbContext something like
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Character>()
.HasRequired(x=> x.Person)
.WithMany(x=> x.Characters)
.HasForeignKey(x=> x.PersonId);
}
also, I suggest you to change your public virtual List<Character> Characters { get; set; }
to public virtual ICollection<Character> Characters { get; set; } , because I'm not sure if the proxy generator (and EF too) will map that list correctly.
EDIT:
I'm thinking that the EF Metadataprovider isn't supplying the correct attribute in description.
Put a KeyAttribute over the Character.CharacterId and Person.PersonID, also, add this line over Character.Person
[Association("Character_Person", "PersonId", "PersonId", IsForeignKey = true)]
and this one over Person.Characters
Association("Character_Person", "PersonId", "PersonId")]<br>
EDIT:
After chat with KitKat we finally found the problem. During proxy generation a call to Assembly.GetExportedTypes crashed complainig it need EF 4.1.
Simple putting
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
in the related config did the tricks
Note: at this link ther's blog post from mine that better explains how to deal with EF5 Code first and WCF Ria Services