I am using ServiceStack for the first time on a brand-new project that started off as a ASP.NET MVC. I am hosting ServiceStack API at the root, so my web.config looks like this:
<system.web>
<httpHandlers>
<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
</handlers>
</system.webServer>
and my App_Start/RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("*");
}
Here's my service:
[Route("/catalogs/{ID}")]
[DataContract]
public class CatalogRequest : IReturn<Catalog>
{
[DataMember]
public int ID { get; set; }
}
[DefaultView("Catalogs")]
public class CatalogService : Service
{
public object Get(CatalogRequest request)
{
return (request.ID == 9999) ? new Catalog() { ID = 9999 } : null;
}
}
I use the following for testing:
public class TestAppHost : AppHostHttpListenerBase
{
public TestAppHost() : base("TestService", typeof(TestAppHost).Assembly) { }
public override void Configure(Funq.Container container)
{
IoC.Configure(container); // IoC is where all Funq configuration is done
}
}
In my VisualStudio unit test I start up the AppHost like this:
[TestClass]
public class TestHelper
{
public const string TEST_HOST_URL = "http://127.0.0.1:8888/";
private static TestAppHost __AppHost;
[AssemblyInitialize]
public static void Initialize(TestContext context)
{
// Start the test app host.
__AppHost = new TestAppHost();
__AppHost.Init();
__AppHost.Start(TEST_HOST_URL);
}
[AssemblyCleanup]
public static void Cleanup()
{
__AppHost.Dispose();
__AppHost = null;
}
}
When I run my test:
[TestMethod]
public void RequestCatalogByID()
{
var client = new JsonServiceClient(TestHelper.TEST_HOST_URL);
var request = new CatalogRequest() { ID = 9999 };
var response = client.Get(request);
Assert.IsNotNull(response);
}
I get a "Not Found" exception even though the URL seems to be correct: http://127.0.0.1:8888/catalogs/9999.
Pointing the browser to http://127.0.0.1:8888/metadata shows the metadata page with no operations.
What am I doing wrong?
Note the assembly you pass in your AppHost Base constructor should be where all your service implementations are (i.e. not your AppHost), so try instead:
public class TestAppHost : AppHostHttpListenerBase
{
public TestAppHost() : base("TestService", typeof(CatalogService).Assembly){}
...
}
Related
I've implemented a WCF Service Library (.Net 4.5) which works fine.
Then I tried to implement Unity DI using a custom Servcie Host Factory. Debugging application I noticed that CreateServiceHost method in my factory not being called so that my service constructor which uses a dependency as parameter not being called and I get this error:
"System.InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host."
my custom Service Host Factory:
namespace Amir.CodingChallenge.WcfService.Unity
{
public class UnityServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
UnityServiceHost serviceHost = new UnityServiceHost(serviceType,baseAddresses);
// I register types in RegisterComponents method by coding.
serviceHost.Container = UnityConfig.RegisterComponents();
return serviceHost;
}
}
}
my service:
namespace Amir.CodingChallenge.WcfService
{
public class MovieService : IMovieService
{
IShowService showService;
public MovieService(IShowService showService)
{
this.showService = showService;
}
...
}
}
and App.Config:
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add service="Amir.CodingChallenge.WcfService.MovieService"
relativeAddress="./MovieService.svc"
factory="Amir.CodingChallenge.WcfService.Unity.UnityServiceHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
<services>
<service name="Amir.CodingChallenge.WcfService.MovieService">
<endpoint address="" binding="wsHttpBinding" contract="Amir.CodingChallenge.WcfService.IMovieService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:49875/Amir.CodingChallenge.WcfService/MovieService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
"Amir.CodingChallenge.WcfService" is my app Assembly name.
Am I doing something wrong in config? Any help would be appreciated.
And the rest of my codes to give further info in below.
UnityConfig class:
namespace Amir.CodingChallenge.WcfService.Unity
{
public static class UnityConfig
{
static UnityContainer container;
public static UnityContainer RegisterComponents()
{
if (container == null)
container = new UnityContainer();
RegisterTypes();
return container;
}
private static void RegisterTypes()
{
container.RegisterType<IShowService, ShowService>(new HierarchicalLifetimeManager());
}
}
}
UnityServiceHost class:
namespace Amir.CodingChallenge.WcfService.Unity
{
public class UnityServiceHost : ServiceHost
{
public UnityContainer Container { set; get; }
public UnityServiceHost()
: base()
{
Container = new UnityContainer();
}
public UnityServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
Container = new UnityContainer();
}
protected override void OnOpening()
{
if (this.Description.Behaviors.Find<UnityServiceBehavior>() == null)
this.Description.Behaviors.Add(new UnityServiceBehavior(Container));
base.OnOpening();
}
}
}
UnityServiceBehavior class:
namespace Amir.CodingChallenge.WcfService.Unity
{
public class UnityServiceBehavior : IServiceBehavior
{
public UnityInstanceProvider InstanceProvider { get; set; }
private ServiceHost serviceHost = null;
public UnityServiceBehavior()
{
InstanceProvider = new UnityInstanceProvider();
}
public UnityServiceBehavior(UnityContainer unity)
{
InstanceProvider = new UnityInstanceProvider();
InstanceProvider.Container = unity;
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
if (cd != null)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
InstanceProvider.ServiceType = serviceDescription.ServiceType;
ed.DispatchRuntime.InstanceProvider = InstanceProvider;
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
public void AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}
}
}
UnityInstanceProvider class:
namespace Amir.CodingChallenge.WcfService.Unity
{
public class UnityInstanceProvider : IInstanceProvider
{
public UnityContainer Container { set; get; }
public Type ServiceType { set; get; }
public UnityInstanceProvider()
: this(null)
{
}
public UnityInstanceProvider(Type type)
{
ServiceType = type;
Container = new UnityContainer();
}
#region IInstanceProvider Members
public object GetInstance(InstanceContext instanceContext, Message message)
{
return Container.Resolve(ServiceType);
}
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
#endregion
}
}
Make sure that you are linking to the UnityServiceHostFactory in your Service Markup
<%# ServiceHost
Language="C#" Debug="true"
Service="WcfServiceApplication.Implementation.ProductService"
Factory="WcfServiceApplication.DependencyInjection.WCF.UnityServiceHostFactory"
%>
Finding the Markup code was the issue for me. Just right click on the Svc and click "View Markup"
Then you can add in the UnityServiceHostFactory as the Factory value
Link to Source of Answer
Ensure that the build is copying the project dll to the correct location.
In my case, I was copying for 'bin\debug' and the correct would be 'bin\'.
I have created a custom role provider for my MVC4 application where I have been successfully able to override CreateRole, GetAllRoles and RoleExists methods and link them to my existing database as follows:
namespace Project.Providers
{
public class MyProvider : System.Web.Security.SqlRoleProvider
{
private MyContext dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
private Repository<MyUser> userRepository;
private Repository<Role> roleRepository;
public MyProvider()
{
this.userRepository = new Repository<MyUser>(dbcontext);
this.roleRepository = new Repository<Role>(dbcontext);
}
public override string[] GetAllRoles()
{
IEnumerable<Role> dbRoles = roleRepository.GetAll();
int dbRolesCount = roleRepository.GetAll().Count();
string[] roles = new string[dbRolesCount];
int i = 0;
foreach(var role in dbRoles)
{
roles[i] = role.Name;
i++;
}
return roles;
}
public override bool RoleExists(string roleName)
{
string[] roles = { "Admin", "User", "Business" };
if(roles.Contains(roleName))
return true;
else
return false;
}
public override void CreateRole(string roleName)
{
Role newRole = new Role();
newRole.Name = roleName;
roleRepository.Add(newRole);
roleRepository.SaveChanges();
}
public override bool IsUserInRole(string userName, string roleName)
{
MyUser user = userRepository.Get(u => u.Username == userName).FirstOrDefault();
Role role = roleRepository.Get(r => r.Name == roleName).FirstOrDefault();
if (user.RoleID == role.RoleID)
return true;
else
return false;
}
}
}
I have been unable to find a way to override the
User.IsInRole(string roleName)
What else must I do so that When I use:
[Authorize(Roles = "Admin")]
It will be based on the role provider that I have set up and not the asp default.
My user class is now as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.Collections;
using System.Security.Principal;
namespace Project.Data
{
public class MyUser : IPrincipal
{
[Key]
public int UserID { get; set; }
[StringLength(128)]
public string Username { get; set; }
.....other properties
public IIdentity Identity { get; set; }
public bool IsInRole(string role)
{
if (this.Role.Name == role)
{
return true;
}
return false;
}
public IIdentity Identity
{
get { throw new NotImplementedException(); }
}
}
}
My stack trace seems to be following over at:
System.Web.Security.RolePrincipal.IsInRole(String role)
So I have tried to implement a custom RolePrincipal in the same manner I set the custom Provider any ideas how I can do this? Not sure what constructor params it takes. Here is my attempt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration.Provider;
using Project.Data;
using System.Web.Security;
using System.Security.Principal.IIdentity;
namespace Project.Principal
{
public class MyPrincipal : System.Web.Security.RolePrincipal
{
private MyContext dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
private Repository<MyUser> userRepository;
private Repository<Role> roleRepository;
public MyPrincipal()
{
this.userRepository = new Repository<MyUser>(dbcontext);
this.roleRepository = new Repository<Role>(dbcontext);
}
public override bool IsInRole(string role)
{
//code to be added
return true;
}
}
}
You just need to override method GetRolesForUser in your custom role provider, instead of the more logical IsUserInRole, because that is what is called by the default implementation that does some unwanted caching.
You override IsInRole in your IPrincipal class, mine in EF looks like this:
public class MyUser : IPrincipal {
//Properties
...
public bool IsInRole(string role) {
if (Roles.Any(m=>m.NameKey.ToLower().Equals(role.ToLower()))) {
return true;
}
return false;
}
}
Then once you add the appropriate sections to your webconfig for both RoleProvider and MembershipProvider you should be good for Authorize attribute.
UPDATE in response to your comments
web Config should look like:
...
<authentication mode="Forms">
<forms loginUrl="~/Login" timeout="2880"></forms>
</authentication>
<authorization>
</authorization>
..
<membership defaultProvider="MyMembershipProvider">
<providers>
<add name="MyMembershipProvider" type="MyApp.Infrastructure.MyMembershipProvider" connectionStringName="connectionstring" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" />
</providers>
</membership>
<roleManager defaultProvider="MyRoleProvider" enabled="true" cacheRolesInCookie="true">
<providers>
<clear />
<add name="MyRoleProvider" type="MyApp.Infrastructure.MyRoleProvider" />
</providers>
</roleManager>
...
In the provider, is the User your IPrincipal?
public MyUser User { get; private set; }
User should have and IIdentity
in MyUser.cs:
...
public virtual ICollection<Role> Roles { get; set; }
public IIdentity Identity { get; set; }
I don't have much additional advice to help troubleshoot from your comments.
UPDATE
Some examples I have been through and found helpful when setting mine up:
http://www.brianlegg.com/post/2011/05/09/Implementing-your-own-RoleProvider-and-MembershipProvider-in-MVC-3.aspx
http://www.mattwrock.com/post/2009/10/14/Implementing-custom-MembershipProvider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx
http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx?Redirected=true
I read many other articles and SO posts on my first run through, but these were things I bothered to bookmark. I took a roles/rights approach to authorization, which is why one of them is geared that way.
To fix this, you need to do 4 updates to your application.
1. Create a class that extends RoleProvider.
namespace MyApp
{
public class MyRoleProvider : RoleProvider
{
public override string ApplicationName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
throw new NotImplementedException();
}
public override string[] GetRolesForUser(string username)
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
// get user roles here using user name.
}
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
return GetRolesForUser(username).Contains(roleName);
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
}
2. Create a custom filter that extends AuthorizeAttribute and overwrite its methods.
public class MyAuthFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var routeValues = new RouteValueDictionary(new
{
controller = "Account",
action = "Login",
});
filterContext.Result = new RedirectToRouteResult(routeValues);
base.HandleUnauthorizedRequest(filterContext);
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
string[] roles = Roles.Split(',');
string userName = HttpContext.Current.User.Identity.Name;
MyRoleProvider myProvider = new MyRoleProvider();
foreach (string role in roles)
{
bool success = myProvider.IsUserInRole(userName, role);
if (success == true)
{
return true;
}
}
return false;
}
3. Configure your custom role provider in your web.config.
<system.web>
<roleManager defaultProvider="MyRoleProvider" enabled="true" cacheRolesInCookie="true">
<providers>
<clear />
<add name="MyRoleProvider" type="MyApp.MyRoleProvider" />
</providers>
</roleManager>
</system.web>
Note: The type here uses the fully qualified namespace and your class name = MyApp.MyRoleProvider. Yours can be different
4. Use your custom filter instead of the default Authorize attribute for your controllers and actions. E.g
[MyAuthFilter]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Title = "Home Page";
return View();
}
}
Using event handlers in my Site-scoped feature's Feature Receiver, I'm adding my HttpHandler to my configuration (I'm new to this, so the code is a bit disjointed, as I've found it here and there).
public override void FeatureActivated(SPFeatureReceiverProperties properties) {
var site = (SPSite)properties.Feature.Parent;
var webApp = site.WebApplication;
if (!webApp.IsAdministrationWebApplication) {
var modification = new SPWebConfigModification("add[#name='SharePointNinjectHttpModule']", "configuration/system.web/httpModules");
modification.Owner = "addSharePointNinjectHttpModule";
modification.Sequence = 0;
modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
modification.Value = #"<add name=""SharePointNinjectHttpModule"" type=""Foo.Bar.SharePointNinjectHttpModule,Foo.Bar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=****************"" />";
webApp.WebConfigModifications.Add(modification);
try {
webApp.WebService.ApplyWebConfigModifications();
webApp.Update();
}
catch (SecurityException e) {
// todo ApplyWebConfigModifications throws "Access Denied" SecurityException when activating via Site Settings
}
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {
var site = (SPSite)properties.Feature.Parent;
var webApp = site.WebApplication;
if (!webApp.IsAdministrationWebApplication) {
var oCollection = webApp.WebConfigModifications;
var iStartCount = oCollection.Count;
for (int c = iStartCount - 1; c >= 0; c--) {
SPWebConfigModification oModification = oCollection[c];
if (oModification.Owner == "addSharePointNinjectHttpModule") {
oCollection.Remove(oModification);
}
}
if (iStartCount > oCollection.Count) {
try {
webApp.WebService.ApplyWebConfigModifications();
webApp.Update();
}
catch (SecurityException e) {
// todo ApplyWebConfigModifications throws "Access Denied" SecurityException when deactivating via Site Settings
}
}
}
}
My SharePoint instance's web.config httpModules section when the feature is not active:
<httpModules>
</httpModules>
And when it is:
<httpModules>
<add name="SharePointNinjectHttpModule" type="Foo.Bar.SharePointNinjectHttpModule,Foo.Bar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=****************" />
</httpModules>
So it seems like the feature receiver event handlers are doing their job (maybe I'm missing something?).
And here's the HttpModule:
using System;
using System.Web;
using Foo.Bar.Models;
using Ninject;
namespace Foo.Bar {
public class SharePointNinjectHttpModule : IHttpModule {
public void Init(HttpApplication context) {
if (Kernel == null) {
Kernel = new StandardKernel();
Kernel.Bind<IRepository>().To<Repository>();
}
}
public static IKernel Kernel { get; private set; }
public void Dispose() {}
private static IKernel GetKernel() {
IKernel result = new StandardKernel();
result.Bind<IRepository>().To<Repository>();
return result;
}
}
}
The Init() method of my HttpModule never fires. When should I expect it to fire, and why isn't that happening?
The following change to FeatureActivated() resolved the problem I was having:
var modification = new SPWebConfigModification("add[#name='SharePointNinjectHttpModule']", "configuration/system.webServer/modules");
I was injecting the module in the wrong section of my web.config.
Original: configuration/system.web/httpModules
Changed: configuration/system.webServer/modules
Once I made the above change, I was correctly adding the httpModule
Once I was correctly adding the httpModule, my Init() fired immediately.
I am trying to develop a WCF rest servie which needs authorization using custom attribute.
I want to send the response as 401 status code if the authorization key is not valid in custom attribute which implements IOperationBehavior and IParameterInspector.
can any one tell me how to send the 401 status code as response from the custom attribute.
Here is the implementation
public class AuthorizationAttribute : Attribute,IOperationBehavior,
IParameterInspector
{
#region IOperationBehavior Members
public void ApplyDispatchBehavior(OperationDescription operationDescription,
System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(this);
}
#endregion
#region IParameterInspector Members
public object BeforeCall(string operationName, object[] inputs)
{
string publicKey =
WebOperationContext.Current.IncomingRequest.Header["Authorization"];
if (publicKey == "592F2D7E-5E9C-400D-B0AE-1C2603C34137")
{
}
else
{
// Here i would like to send the response back to client
with the status code
}
}
return null;
}
#endregion
}
[Authorization]
public bool signin(string username, string password)
{
}
Throw a WebFormatException
throw new WebFaultException(HttpStatusCode.Unauthorized);
If you're using WCF Rest Starter kit you can also do:
throw new Microsoft.ServiceModel.Web.WebProtocolException(System.Net.HttpStatusCode.Unauthorized, "message", ex);
That method has some more overloads if you need.
public string CreateError(int code ,string description)
{
Context.Response.StatusCode = code;
Context.Response.StatusDescription = description;
Context.ApplicationInstance.CompleteRequest();
return null;
}
Then from your web service methods just use this to return errors example:
return CreateError(403, "Request denied by server");
If aspnetcompatibilityMode cannot be enabled in your WCF services, then you can do as below.
You have to intercept the message and set the status code in HttpResponseMessageProperty in the wcf message. I use a CustomErrorHandler for doing that and it works fine.
public class CustomErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
fault.Properties[HttpResponseMessageProperty.Name] = new HttpResponseMessageProperty()
{
StatusCode = statusCode
};
}
}
Below code is for injecting CustomErrorHandler into the ServiceBehavior.
public class CustomServiceBehaviour : IServiceBehavior
{
... other IServiceBehavior methods
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
channelDispatcher.ErrorHandlers.Add(new CustomErrorHandler());
}
}
}
Then in web.config use the serviceBehavior
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="CustomServiceBehavior" type="MyNamespace.CustomServiceBehavior, MyAssembly" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="CustomBehavior">
<CustomServiceBehavior />
</behavior>
</serviceBehaviors>
</behaviors>
<service behaviorConfiguration="CustomBehavior" name="SomeService">
<endpoint ..../>
</service>
</system.serviceModel>
I am using MVVM pattern for Silverlight.
I have these projects:
MVVMDemo.Data (Ria services link set to MVVMDemo.Data.Web)
MVVMDemo.Data.Web (Contains all RIA services) MVVMDemo.Data.ViewModels
MVVMDemo.Data.Models MVVMDemo (contains all views)
MVVMDemo.Data.Common (contains all interfaces)
This is my RIA services class:
namespace MVVMDemo.Data.Web
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
[EnableClientAccess()]
public class UserServices : LinqToEntitiesDomainService<IssueVisionEntities>
{
public IQueryable<User> GetUsersByLimit(int skip , int take)
{
return this.ObjectContext.Users.Skip(skip).Take(take);
}
public IQueryable<User> GetUsers()
{
return this.ObjectContext.Users;
}
public void InsertUser(User user)
{
if ((user.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(user, EntityState.Added);
}
else
{
this.ObjectContext.Users.AddObject(user);
}
}
public void UpdateUser(User currentUser)
{
this.ObjectContext.Users.AttachAsModified(currentUser, this.ChangeSet.GetOriginal(currentUser));
}
public void DeleteUser(User user)
{
if ((user.EntityState == EntityState.Detached))
{
this.ObjectContext.Users.Attach(user);
}
this.ObjectContext.Users.DeleteObject(user);
}
}
}
This is my model which calls RIA services :-
namespace MVVMDemo.Models
{
[Export(typeof(IUserModel))]
public class UserModel : IUserModel
{
private const int PAGESIZE = 10;
private int skip = 0;
private UserServices _context;
private UserServices Context
{
get
{
if (_context == null)
{
_context = new UserServices();
}
return _context;
}
}
public void GetAllUsersAysnc()
{
PerformQuery<User>(Context.GetUsersQuery(), GetAllUsersAsyncComplete);
}
private void PerformQuery<T>(EntityQuery<T> query , EventHandler<EntityResultArgs<T>> eventHandler) where T:Entity
{
this.Context.Load<T>(query, LoadBehavior.RefreshCurrent, r =>
{
if (eventHandler != null)
{
try
{
if (r.HasError)
{
eventHandler(this, new EntityResultArgs<T>(r.Error));
r.MarkErrorAsHandled();
}
else
eventHandler(this, new EntityResultArgs<T>(r.Entities));
}
catch (Exception ex)
{
eventHandler(this, new EntityResultArgs<T>(ex));
}
}
},null);
}
public event EventHandler<EntityResultArgs<Data.Web.User>> GetAllUsersAsyncComplete;
public void GetAllUsersByLimit()
{
PerformQuery<User>(Context.GetUsersByLimitQuery(skip,PAGESIZE), GetAllUsersByLimitAsyncComplete);
}
public event EventHandler<EntityResultArgs<Data.Web.User>> GetAllUsersByLimitAsyncComplete;
}
Whenever i run the method GetAllUsersAysnc i always get this error :-
http://img408.imageshack.us/img408/6150/62968542.jpg
This is my app.config in MVVMDemo.Data.Web
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="DomainServiceModule" preCondition="managedHandler"
type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
<connectionStrings>
<add name="IssueVisionEntities" connectionString="metadata=res://*/IssueVisionModel.csdl|res://*/IssueVisionModel.ssdl|res://*/IssueVisionModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=TAPESH\MSSQLSERVER2008;Initial Catalog=IssueVision;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.web>
<httpModules>
<add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</httpModules>
</system.web>
</configuration>
And this is my web.config of Asp.Net website which is hosting the silverlight application
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
</configuration>
I have no idea what is happening and I am a beginner in RIA services.