I'm creating an app based on SOA, I've created WCF Service Project using Framework 4.0, in that I'm using Entity framework, in WCF operation Contract method I'm using the class generated by the EF, but the WCF can't recognize these objects, when I checked those classes in designer mode, they are like
[EdmEntityTypeAttribute(NamespaceName="quizTestDBModel", Name="tbl_adminUser")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class tbl_adminUser : EntityObject
{
#region Factory Method
/// <summary>
/// Create a new tbl_adminUser object.
/// </summary>
/// <param name="adminUserId">Initial value of the adminUserId property.</param>
public static tbl_adminUser Createtbl_adminUser(global::System.Int32 adminUserId, global::System.String name, global::System.String userid, global::System.String password)
{
tbl_adminUser tbl_adminUser = new tbl_adminUser();
tbl_adminUser.adminUserId = adminUserId;
return tbl_adminUser;
}
#endregion
#region Primitive Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 adminUserId
{
get
{
return _adminUserId;
}
set
{
if (_adminUserId != value)
{
OnadminUserIdChanging(value);
ReportPropertyChanging("adminUserId");
_adminUserId = StructuralObject.SetValidValue(value);
ReportPropertyChanged("adminUserId");
OnadminUserIdChanged();
}
}
}
private global::System.Int32 _adminUserId;
partial void OnadminUserIdChanging(global::System.Int32 value);
partial void OnadminUserIdChanged();
#endregion
}
When I use this class in my operation contract as
int adminRegister(tbl_adminUser _adminUser);
It give error on that method, "The operation is not supported in WCF Test Client, because it uses type tbl_adminUser"
Thanks
If you are passing platform-specific data across a service boundary, then you are not using SOA.
Entity Framework classes are specific to .NET and to Entity Framework. Do not pass them across a service boundary.
I also note that you want to subject your clients to your naming conventions (tbl_adminUser), as well as the fact that there are tables involved. Why do the callers of your service need to know anything about the fact that you've implemented the concept of an "admin user" by using a table named tbl_adminUser?
You should create yourself a Data Transfer Object class named, for instance, AdminUser. It should have properties for all of the interesting public aspects of an admin user (apparently, just AdminUserId). It should have no behavior at all - just data.
This is the class that should be sent by and received from your service.
And, yes, you'll have to implement mapping code.
The error just says that WCF Test client doesn't support your contract but it doesn't mean that WCF itself doesn't. WCF Test client is for testing the most common scenarios and it doesn't support all WCF features. Write test application or use more powerful test tool like SoapUI to validate that your service works.
Also follow #John's advices because your current design has awful naming convention, it exposes EntityObject based entities and it is far from SOA. By your description it is simple CRUD exposed as a service. You will achieve similar result with WCD Data Services much faster.
Related
I am trying to consume WCF in my MVC web app. I have implemented the channel factory for instantiating the proxy client.
I am stuck at a point. Here is the code highlight -
I created a proxy base class where i am creating the channel :
public abstract class ServiceProxyBase<T> : IDisposable where T : class
For creating teh proxy wrapper class i have inherited this base class as :
public class ProxyWrapper : ServiceProxyBase<IMyService>,IMyService
Here "IMyService" is the WCf contract.
Now, in the controllers i have added overloaded constructors as :
public class AccountController : Controller
{
private IMyService businessService;
public AccountController(IMyService _businessService)
{
this.businessService = _businessService;
}
}
For injecting dependency I have included unity.mvc4 package.
It works fine when I am using the following code :
container.RegisterType<IMyService, ProxyWrapper>();
This works as long as the ProxyWrapper is inheriting the IMyService interface directly. If i remove the inheritance like
public class ProxyWrapper : ServiceProxyBase<IMyService>
it gives an error while registering type.
I would like to have a way without inherting the contract in the proxy wrapper. I have spent almost a day trying to fix this. But am able to figure out a solution.
Please give your valuable suggestions on this.
If I understand correctly, your application is using a WCF service but the functionality your application needs is limited compared to the functionality that the service offers (it contains more methods than you need). According to the Interface Segregation Principle, "no client should be forced to depend on methods it does not use" and the Dependency Inversion Principle states that clients own the abstraction.
In other words, you should define your own interface that the application should use and define an implementation that wraps (i.e. composition over inheritance) the generated WCF proxy class.
For instance:
public interface IMyApplicationService
{
object GetStuff();
void PutStuff(object instance);
}
public class MyServiceApplicationProxy : IMyApplicationService
{
private readonly ProxyWrapper wcfProxy;
public MyServiceApplicationProxy(ProxyWrapper wcfProxy) {
this.wcfProxy = wcfProxy;
}
public object GetStuff() {
return this.wcfProxy.GetStuff();
}
public void PutStuff(object instance) {
this.wcfProxy.PutStuff(instance);
}
}
To make application development easier, makes your code easier to read, maintain and test.
You might even want to change the methods of your interface to better suit your application needs. Remember: the client defines the interface! So that might mean that you need to do more mapping inside the MyServiceApplicationProxy class to map adapt your core domain to the contract of the external web service. Don't let the external WCF service's contract leak into your core domain.
I am trying a host a service where there is a method that returns the following type:
[DataContract]
[Obfuscation(ApplyToMembers = true, Exclude = true)]
[Serializable]
public class Output
{
[DataMember]
public DataSet dsOutput{get;set;}
}
The method signature is as follows:
[OperationContract]
[WebGet]
function Output matchData(DataSet pDSSide1,DataSet pDSSide2)
{
return new Output();
}
On browsing the service I encounter the following exception:
System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension:System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://tempuri.org/:TesterTool ---->
System.Runtime.Serialization.InvalidDataContractException: Type 'System.Data.DataRow' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
`
Any suggestions.
It's not a good practice to send a DataTable over a service.
As stated by govindaraj here:
The best way is to use custom collection of custom object.
If you're using 2.0, then you can use generic collection instead of
custom collection to reduce code.
How?
Create a custom data object (containing only private fields and public properties for each field) that is similar to each row in the
datatable.
Create a layer that will do all database (in this case, dataset) access and translation to the custom object.
All client code will access that layer.
I'm working on an application which should validate the model based on some metadata saved in a database. The purpose of this is to allow administrators change how some models are validated, without changing the code, depending on clients' preferences. The changes are applied for the entire application, not for specific users accessing it. How it is changed, doesn't matter at the moment. They could be modified directly on the database, or using an application. The idea is that they should be customizable.
Let's say i have the model "Person" with the property "Name" of type "string".
public class Person
{
public string Name { get; set; }
}
This model is used by my app which is distributed and istalled on several servers. Each of them is independent. Some users may want the Name to have maximum 30 letters and to be required when creating a new "Person", others may want it to have 25 and not to be required. Normally, this would be solved using data annotations, but those are evaluated during the compile time and are somehow "hardcoded".
Shortly, I want to find a way to customize and store in a database how the model validates, without the need of altering the application code.
Also, it would be nice to work with jquery validation and have as few request to database(/service) as possible. Besides that, i can't use any known ORM like EF.
You could create a custom validation attribute that validates by examining the metadata stored in the database. Custom validation attributes are easy to create, simply extend System.ComponentModel.DataAnnotations.ValidationAttribute and override the IsValid() method.
To get the client side rules that work with jQuery validation you will need to create a custom adapter for the type of your custom validation attribute that extends System.Web.Mvc.DataAnnotationsModelValidator<YourCustomValidationAttribute>. This class then needs to be registered in the OnApplicationStart() method of your Global.asax.
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(YourCustomValidationAttribute), typeof(YourCustomAdapter));
Here's an example adapter:
public class FooAdapter : DataAnnotationsModelValidator<FooAttribute>
{
/// <summary>
/// This constructor is used by the MVC framework to retrieve the client validation rules for the attribute
/// type associated with this adapter.
/// </summary>
/// <param name="metadata">Information about the type being validated.</param>
/// <param name="context">The ControllerContext for the controller handling the request.</param>
/// <param name="attribute">The attribute associated with this adapter.</param>
public FooAdapter(ModelMetadata metadata, ControllerContext context, FooAttribute attribute)
: base(metadata, context, attribute)
{
_metadata = metadata;
}
/// <summary>
/// Overrides the definition in System.Web.Mvc.ModelValidator to provide the client validation rules specific
/// to this type.
/// </summary>
/// <returns>The set of rules that will be used for client side validation.</returns>
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return new[] { new ModelClientValidationRequiredRule(
String.Format("The {0} field is invalid.", _metadata.DisplayName ?? _metadata.PropertyName)) };
}
/// <summary>
/// The metadata associated with the property tagged by the validation attribute.
/// </summary>
private ModelMetadata _metadata;
}
This may also be useful if you would like to asynchronously call server side validation http://msdn.microsoft.com/en-us/library/system.web.mvc.remoteattribute(v=vs.108).aspx
I have my service layer, entities and DTOS in a separeted assembly called CCL.Data
The problem:
All My application is referencing the service layer directly using interfaces and IoC.
For example, I have an interface in my CCL.Data assembly called ICustomerService it depends on ICustomerRepository that depends on MyContext. All my application is referencing ICustomerService to call its methods....... so far no problem.
So I created a WCF Project.... referencing CCL.Data in this project....
I create a new Service, but int this case below, I would need to change all points in my application that call ICustomerService to WCFCustomerServiceClient, does exists a better way without cause a big impact in my project?
[ServiceContract]
public interface IWCFCustomerService
{
[OperationContract]
CustomerDTO GetCustomerById(int id);
}
public class WCFCustomerService : IWCFCustomerService
{
ICustomerService _customerService;
public WCFCustomerService()
{
MyContext context = new MyContext();
ICustomerRepository customerRep = new CustomerRepository(context);
_customerService = new CustomerService(customerRep);
}
public CustomerDTO GetCustomerById(int id)
{
return _customerService.GetCustomerById(id);
}
}
Tks,
William
Do you need to redefine IWCFCustomerService in place of ICustomerService? Is it not possible just to add ServiceContract attributes to your original ICustomerService interface (they will just get ignored by non WCF code)? (Its true that this does give you a dependancy on ServiceModel - but I cant see a way out of that).
Note also that if you use a ServiceRefernce to generate proxy code then the code generated will include a your service interface in different namespace for use clientside. Its worth noting that your not abliged to use that version of the interface (which could be annoying if you have a proxy and not proxy implimentation) but can still use the org interface definition either from a dll or compiled into your client.
I need to pass a Context object from EF into a WCF method.
Normally, I create the Context object in the WCF method and dispose of it right before the end of the method call which works just fine for most of my methods.
However, I need to pass the Context object (specifically the DBContext) over from the MVC controller to my specific WCF method because I have caching enabled for some lookup tables. I need this specific Context object passed over (the one I set in the Application_Start method of the Global.asax file) rather than what I do in the sentence above because I use this specific object for the SqlDependency. If I try and create the DBContext object brand new, I can't use the SqlDependency becuase I will get an error informing me that the SqlDependency needs to be enabled before the database call.
The problem is that I'm getting the following error (shortened for brevity) when I try and start my WCF Test Client tool which I know has something to do with not properly declaring a KnownType attribute (ie the DBContext object). Note that the WCF project compiles just fine. I need some help with this specific part since I have never used a KnownType in my WCF service. They have all been simple types (int, string, etc).
Error: Cannot obtain Metadata from http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex
If this is a Windows (R) Communication Foundation service to which you
have access, please check that you have enabled metadata publishing at
the specified address. For help enabling metadata publishing, please
refer to the MSDN documentation at
http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange
Error URI:
http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex
Metadata contains a reference that cannot be resolved:
I have the following OperationContract code in my WCF service:
[OperationContract]
IEnumerable<Category> GetCategories(YeagerTechEntities DbContext);
I have the following DataContract code in my WCF service:
namespace YeagerTechModel
{
[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(YeagerTechEntities))]
public partial class Category
{
public Category()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CategoryID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public virtual ICollection<Project> Projects { get; set; }
}
}
Finally, the following is my WCF method:
public IEnumerable<YeagerTechModel.Category> GetCategories(YeagerTechEntities DbContext)
{
//YeagerTechEntities DbContext = new YeagerTechEntities();
DbContext.Configuration.ProxyCreationEnabled = false;
IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0).AsCached("Categories").ToList();
//IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0);
CloseConnection(DbContext);
return category;
}
You need singleton object following registry / service locator pattern. This object will hold reference to your global objects. For example at application start you will fill this object with your context using SqlDependency and you will use the registry to access this context in your controller's actions and service's operations.
Anyway work with this very carefully. SqlDependency and EF doesn't play nice together because it will make your context long living. Long living context is in most cases anti-pattern. Never ever use that context for anything else then loading cached data. Don't use it for data modification or loading non cached relations! Load entities as non-tracked (AsNoTracking extension method on query) in the first query and turn off proxy creation and lazy loading for that context.
Also be aware that query in EF is always executed in the database. I'm not sure what your AsCached is supposed to do but I somehow doubt it will work. What you need is probably:
var category = DbContext.Categories.Local
.Where(p => p.CategoryID > 0)
.ToList();
I would not use SqlDependency with EF. I would use ADO.NET and SQL directly. For caching in EF I would check EF Caching provider to use second level cache which is in most cases enough.