I have a WCF with a method that return a class of generics like this
public class Response<TOutputContract>
{
public TOutputContract Output { get; set; }
public bool Status { get; set; }
}
i have a project with Service Reference to that WCF.
When i try to update the service reference, visual studio create another class without generic.
public class ResponseTOutputContract
{
public TOutputContract Output { get; set; }
public bool Status { get; set; }
}
How can i generate the same class in the service(with generic)?
Your [DataContract] would have to expose the generic:
[DataContract]
public class GenericSample<TGeneric>
{
private TGeneric id;
[DataMember]
public TGeneric Id
{
get { return id; }
set { id = value; }
}
}
Once we've outlined our DataContract you would implement your ServiceContract.
[ServiceContract]
public interface IBoundGeneric
{
[OperationContract]
GenericSample<int> GetObject(int id);
}
This is where you will specify the type, so depending on your implementation will vary on how you structure your DataContract.
Related
I have a model class that is extended from the realm object. In some cases, I use this model as both realm model and POST operations. Currently, the realm IList properties unable to support setter options. Is there any option or way to achieve this?
Here is my current code:
[JsonObject]
public class Product : RealmObject, IProduct
{
[MapTo("name")]
[JsonProperty("name")]
public string Name { get; set; }
[MapTo("skuDetails")]
[JsonProperty("skuDetails")]
public IList<SkuDetail> SkuDetails { get; }
}
My requirement :
[JsonObject]
public class Product : RealmObject, IProduct
{
[MapTo("name")]
[JsonProperty("name")]
public string Name { get; set; }
[MapTo("skuDetails")]
[JsonProperty("skuDetails")]
public IList<SkuDetail> SkuDetails { get; set; }
}
you need to derive your class according your need.
this is totally possible like the code below:
public interface ITest
{
IList<object> SkuDetails { get; }
}
public class OutTest : ITest
{
public IList<object> SkuDetails { get; set; }
}
Please note that extending property method is supported however opposite of it is not.
Ex:
public interface ITest
{
IList SkuDetails { get; set; }
}
public class OutTest : ITest
{
public IList<object> SkuDetails { get; }
}
is not possible.
I am new to WCF; this is my first try.
I created two projects using the Microsoft Visual Studio Express 2013 for Web. One is "WCF Service Application" and the other is a MVC Web application; the Web application consumes the WCF service.
I know the basics of making the communication possible between the Web application and the WCF service.
I will jump directly to to problem;
If I've two model classes represent two entities from the Database:
Stock:
public partial class Stock
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<int> UserId { get; set; }
public virtual User User { get; set; }
}
User:
public partial class User
{
public User()
{
this.Stocks = new HashSet<Stock>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Stock> Stocks { get; set; }
}
I need to map them to the WCF service correctly as [DataContract] classes; How?
This is my try:
[ServiceContract]
public interface IService1
{
// List all Stocks
[OperationContract]
List<Stock> GetStocks();
}
[DataContract]
public class WCF_Stock
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public Nullable<int> UserId { get; set; }
[DataMember]
public virtual WCF_User User { get; set; }
}
[DataContract]
public class WCF_User
{
// Does this constructor require any special attributes?
public WCF_User()
{
this.WCF_Stocks_Collection = new HashSet<WCF_Stock>();
}
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual ICollection<WCF_Stock> WCF_Stocks_Collection { get; set; }
}
Please Note the comment question above: Does this constructor require any special attributes?
Implementation for IService1:
public class Service1 : IService1
{
private StockPEntities dbStock = new StockPEntities();
public List<Stock> GetStocks()
{
return dbStock.Stocks.ToList<Stock>();
}
}
I consume it in the Web application:
public class WCFConsumerController : Controller
{
ServiceReference1.Service1Client wcfService = new ServiceReference1.Service1Client();
public ActionResult Index()
{
return View(wcfService.GetStocks());
}
}
It gives An existing connection was forcibly closed by the remote host
But; before adding the User entity to the database, and of course before adding the WCF_User [DataContract] to the WCF Service; that is when there was only the WCF_Stock alone, like this:
[DataContract]
public class WCF_Stock
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
The code at the Web application that consumes the WCF service works correctly; that is, this line returns a View with Data:
return View(wcfService.GetStocks());
You don't have to create separate WCF_Stock class, and you don't have to mark classes using attributes.
I think that you have problem with lazy loading mechanism in Entity Framework. Try to disable it in GetStocks method using following code:
dbStock.Configuration.LazyLoadingEnable = false;
As part of my WCF web service's return message I created three custom classes. They are implemented in my the return message class, which contains a DataContract decoration (pretty sure that's how it's supposed to be done).
However when I run the Visual Studio 2012 WCF Test Client I get the following error message (highlighted in black)
App Code
Class exposed to the program calling the web service. This calls a method with a return type of CloneMessage (detailed below)
namespace OKeeffeDataService
{
public class MonetToDss : IMonetToDss
{
private AgentCloneRules _agentClone;
public MonetToDss()
{
_agentClone = new AgentCloneRules();
}
[PrincipalPermission(SecurityAction.Demand, Role = "AgentPaymentUpdater")]
public CloneMessage CloneRequest(string agentId)
{
//TODO: Validate agent Id?
EventLog.WriteEntry("OKeeffe", "Made it to CloneRequest", EventLogEntryType.Information);
return _agentClone.CloneRequest(agentId);
}
}
}
App Code Interface
namespace OKeeffeDataService
{
[ServiceContract]
public interface IMonetToDss
{
[OperationContract]
CloneMessage CloneRequest(string agentId);
}
}
Clone Message Class
This is the class the WCF service returns. The AgentClone and RelationshipCode classes were generated by the Entity Framework and extend System.Data.Objects.DataClasses.EntityObject. AgentAddresses is a custom class I wrote with standard string properties representing Street, City, State, Zip, etc (listed below).
namespace BusinessEntities
{
[DataContract]
public class CloneMessage : ICloneMessage
{
[DataMember]
public AgentClone AgentInformation { get; set; }
[DataMember]
public IList<AgentAddress> AgentAddresses { get; set; }
[DataMember]
public IList<RelationshipCode> RelationshipCodes { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
public CloneMessage(){}
public CloneMessage(AgentClone agtTran, IList<AgentAddress> addresses, IList<RelationshipCode> relationshipCodes)
{
this.AgentInformation = agtTran;
this.AgentAddresses = addresses;
this.RelationshipCodes = relationshipCodes;
}
}
}
Clone Message Interface
namespace BusinessEntities
{
public interface ICloneMessage
{
AgentClone AgentInformation { get; set; }
IList<AgentAddress> AgentAddresses { get; set; }
IList<RelationshipCode> RelationshipCodes { get; set; }
String ErrorMessage { get; set; }
}
}
EDIT
Adding the enum and classes to the post
AgentAddresses class
AddressType is custom enum.
namespace BusinessEntities
{
[DataContract]
public class AgentAddress : IAgentAddress
{
[DataMember]
public AddressTypeValues.AddressType AddressType { get; set; }
[DataMember]
public string Street1 { get; set; }
[DataMember]
public string Street2 { get; set; }
[DataMember]
public string Street3 { get; set; }
[DataMember]
public string City { get; set; }
[DataMember]
public string State { get; set; }
[DataMember]
public string ZipCode { get; set; }
}
}
AddressTypeValues enum
namespace BusinessEntities
{
public class AddressTypeValues
{
[DataContract(Name = "AddressType")]
public enum AddressType
{
[EnumMember(Value = "Home")]
Home,
[EnumMember(Value = "Mailing")]
Mailing,
[EnumMember(Value = "Location")]
Location,
[EnumMember(Value = "Other")]
Other
}
}
}
AgentClone and RelationshipCode class headers
[EdmEntityTypeAttribute(NamespaceName="AgentResourcesReturn", Name="AgentClone")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class AgentClone : EntityObject
[EdmEntityTypeAttribute(NamespaceName="AgentResourcesReturn", Name="RelationshipCode")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class RelationshipCode : EntityObject
Try adding the following known types to your CloneMessage data contract.
[DataContract]
[KnownType(typeof(AgentClone))]
[KnownType(typeof(AgentAddress))]
[KnownType(typeof(RelationshipCode))]
public class CloneMessage : ICloneMessage
And this AddressTypeValues type to the AgentAddress class.
[DataContract]
[KnownType(typeof(AddressTypeValues))]
public class AgentAddress : IAgentAddress
Once you do this, rebuild the service and try to browse it again the WCF test client.
Add DataContract attribute to AgentClone & RelationshipCode classes
If AddressTypeValues.AddressType is Enum type, then apply the DataContractAttribute attribute to the type. You must then apply the EnumMemberAttribute attribute to each member that must be included in the data contract. refer - http://msdn.microsoft.com/en-us/library/aa347875(v=vs.110).aspx
Add the below attributes to CloneMessage class
[KnownType(typeof(AgentAddress))]
[KnownType(typeof(RelationshipCode))]
try changing like this..
namespace BusinessEntities
{
[DataContract(Name = "AddressType")]
public enum AddressType
{
[EnumMember(Value = "Home")]
Home,
[EnumMember(Value = "Mailing")]
Mailing,
[EnumMember(Value = "Location")]
Location,
[EnumMember(Value = "Other")]
Other
}
}
[DataMember]
public AddressType AddressType { get; set; }
If you are still facing issue, then I am 100% sure that the problem is with AgentInformation/RelationshipCodes. Just comment these two members of CloneMessage class and try. you will get some pointers. If you don't face issue after commenting, then it is something to do with EntityObject. similar issue - Why doesn't WCFTestclient understand standard EF objects but understands STE objects
How to use DataContract with inheritance? Will code below work?
[DataContract]
public class ConsoleData
{
[DataMember]
public String Description { get; set; }
}
[DataContract]
public class SomeData : ConsoleData
{
[DataMember]
public int Volume { get; set; }
......
Yes, that would work.
The DataContractAttribute has Inherited set to false, so it is necessary to apply the attribute to both the child class and the parent class (as you have done in the question).
You would need to use the KnownType attribute if you want to use your data contracts with polymorphism.
For example
[ServiceContract]
interface MyWcfContract
{
[OperationContract]
HandleData(ConsoleData contractData);
}
If you invoked the method like so:
SomeData someData = new SomeData { Description = "Test", Volume = 30 };
// The method is expecting a ConsoleData instance,
// I'm passing a SomeData instance instead
myWcfProxy.HandleData(someData);
Then the deserializer on the service end will not know that it's an instance of SomeData, just an instance of ConsoleData which it was expecting.
The way to fix this is to register the SomeData class as a known type of the ConsoleData.
[DataContract]
[KnownType(typeof(SomeData))]
public class ConsoleData
{
[DataMember]
public String Description { get; set; }
}
[DataContract]
public class SomeData : ConsoleData
{
[DataMember]
public int Volume { get; set; }
......
You'll need to use the KnownType attribute if you are using the XmlSerializerFormat for your ServiceContract:
[DataContract]
public class ConsoleData
{
[DataMember]
public String Description { get; set; }
}
[DataContract, KnownType(typeof(ConsoleData))]
public class SomeData : ConsoleData
{
[DataMember]
public int Volume { get; set; }
}
I'm using interfaces in this case mostly as a handle to an immutable instance of an object. The problem is that nested interfaces in C# are not allowed. Here is the code:
public interface ICountry
{
ICountryInfo Info { get; }
// Nested interface results in error message:
// Error 13 'ICountryInfo': interfaces cannot declare types
public interface ICountryInfo
{
int Population { get; }
string Note { get; }
}
}
public class Country : ICountry
{
CountryInfo Info { get; set; }
public class CountryInfo : ICountry.ICountryInfo
{
int Population { get; set; }
string Note { get; set; }
.....
}
.....
}
I'm looking for an alternative, anybody would have a solution?
VB.NET allows this. So, you can create a VB.NET assembly only with the interface definitions that you need:
Public Interface ICountry
ReadOnly Property Info() As ICountryInfo
Public Interface ICountryInfo
ReadOnly Property Population() As Integer
ReadOnly Property Note() As String
End Interface
End Interface
As for the implementation, C# does not support covariant return types, so you must declare your class like this:
public class Country : ICountry {
// this property cannot be declared as CountryInfo
public ICountry.ICountryInfo Info { get; set; }
public class CountryInfo : ICountry.ICountryInfo {
public string Note { get; set; }
public int Population { get; set; }
}
}
If the end goal is to use this with dependency injection, what's wrong with injecting them into each other instead of nesting?
public interface ICountry
{
ICountryInfo Info { get; }
}
public interface ICountryInfo
{
int Population { get; set; }
string Note { get; set; }
}
and implement as:
public class Country : ICountry
{
private readonly ICountryInfo _countryInfo;
public Country(ICountryInfo countryInfo)
{
_countryInfo = countryInfo;
}
public ICountryInfo Info
{
get { return _countryInfo; }
}
}
public class CountryInfo : ICountryInfo
{
public int Population { get; set; }
public string Note { get; set;}
}
Then once you set up your bindings for ICountry & ICountryInfo, CountryInfo will inject into Country whenever Country is injected.
You could then restrict the binding, if you wanted, to only inject CountryInfo into Country and nowhere else. Example in Ninject:
Bind<ICountry>().To<Country>();
Bind<ICountryInfo>().To<CountryInfo>().WhenInjectedInto<Country>();
You can use namespaces like this:
namespace MyApp
{
public interface ICountry { }
namespace Country
{
public interface ICountryInfo { }
}
}
Then in MyApp namespace you can use Country.ICountryInfo which is close to your requirement. Also using alias helps make the code clear.
This will work just fine, no need to nest:
public interface ICountry
{
ICountryInfo Info { get; }
}
public interface ICountryInfo
{
int Population { get; }
string Note { get; }
}
If ICountryInfo has no reason to exist outside ICountry, then why shouldn't you just put the properties of ICountryInfo in ICountry and dismiss the idea of nested interfaces?
An interface that hasn't a meaning of its own without another interface doesn't make sense to me, as an interface on itself is useless if not implemented by a class.