none
Service code not hitting my [WebGet]?

    Question

  • When my wcf dataservice is called it hits the code where I have two strings declared and then jumps right to the Entity Data Model and never hits my [WebGet] to call my stored procedure and instead just makes a call to the table itself. 

     Can someone let me know why it is just hitting the table and not my method to call my stored procedure?

    using System;
    using System.Collections.Generic;
    using System.Data.Services;
    using System.Data.Services.Common;
    using System.Linq;
    using System.ServiceModel.Web;
    using System.Web;
    using System.Web.Services;
    
    namespace BAHelloWorld.Web
    {
    
        public class wcfDS_reprtsUsers : DataService<cv4Entities>
        {
    
            // This method is called only once to initialize service-wide policies.
            public static void InitializeService(DataServiceConfiguration config)
            {
                // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
                // Examples:
               // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
                config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
                //config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
    
                // Set the data service version to V2 to support paging.
                config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
                //config.SetEntitySetPageSize("Orders", 2);
                //config.SetEntitySetPageSize("Order_Details", 2);
    
            }
            string UserName = "eanor";
            string CaseSense = "N";
    
    
            //[WebGet]
            [WebMethod]
            public IQueryable<GetUser_Result> GetUser(string CaseSense, string UserName)
            {
                   return this.CurrentDataSource.GetUser(CaseSense, UserName).AsQueryable();
               // return this.CurrentDataSource.GetUser.Where(o => o.UserName == UserName);
            }


     

    Tuesday, November 16, 2010 1:50 PM

Answers

  • It's hard to read your code. Seems you didn't use Load method.

    For query functions, you should use Load method to load them:

    DataServiceCollection<User> UserList = new DataServiceCollection<User>();

    UserList.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(LoadCompleted);

    var query = Context.CreateQuery<User>("GetUser").AddQueryOption("CaseSense", YourCaseSense).AddQueryOption("UserName", YourNameName);

    UserList.LoadAsync(query);


    void LoadCompleted(object sender, LoadCompletedEventArgs e)
    {
                if (e.Error != null)
                {              
                    ErrorWindow.Create(e.Error);                                           
                }

                else  // UserList should be filled now

               {       

               }

    }


    See this thread for more on how to consume WCF data service in Silverlight:

    http://betaforums.silverlight.net/forums/t/208481.aspx

    Tuesday, November 16, 2010 4:34 PM
  • sladapter, I dropped that code in to my wcfDS_reprtsUsers.svc.cs code, but it doesn't fall into or trigger it.  Have you managed to return data from a stored procedure with complex types returning more than one column of data?

    I just tried this case. Yes, I can confirm what you saw. If I map a StoredProcedure result to a ComplexType, no data from WCF data service would return to Silverlight. Actually the Load call would fail because there is no Key attribute tagged for the Complex Type in the generated code. I had to manually add the key tag in the generated code in order for the call to pass through.

        [global::System.Data.Services.Common.DataServiceKeyAttribute("id")]
        public partial class GetTest_Result : global::System.ComponentModel.INotifyPropertyChanged
        {...

        }

    Even the call can pass through, still no data returned in the collection.

    But if I map the StoredProcedure result to the corresponding table (entity type), everything works fine.

    I don't know if you can map your SP result to the User table or not. If you can, it should solve this problem.

    I guess the problem is with the built-in DataService de-serializer. If you do not rely on the DataService de-serializer, you can get the Xml data back by using WebClient:

    WebClient wc = new WebClient();
    wc.DownloadStringCompleted += (s, e) =>
    {
        string xml = e.Result; // you can de-serialize it yourself
    };
    wc.DownloadStringAsync(new Uri(Application.Current.Host.Source, "../YourService.svc/GetUser?CaseSense=XXX&UserName=YYY"));



    Sunday, November 21, 2010 10:34 PM

All replies

  • Turn on your ServiceOperationAccessRule:

    config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

    or

    config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead); // if you want read only access

    Tuesday, November 16, 2010 1:59 PM
  • Thanks for the reply sladapter.  I uncommented that line out and set to AllRead,

    config.SetServiceOperationAccessRule("*", ServiceOperationRights .AllRead);

    but still it's continuing to skip my WebGet and continue to the entity datamodel (code below)

       public crv4Entities() : base("name=crv4Entities", "crv4Entities")
            {
                this.ContextOptions.LazyLoadingEnabled = true;
                OnContextCreated();
            }
     
    Also, if I test the service I receive the following (so I'm guessing it's there, but from examples online I see they have data and I dont):

    <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
      <GetUser xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices" />

    I dont know if it will help but here is my class in the ViewModel folder:

    using System;
    using BAHelloWorld.wcfDStry;
    using System.Collections.ObjectModel;
    using System.Data.Services.Client;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace BAHelloWorld.ViewModel
    {
        public class UserVM : ViewModelBase
        {
            ObservableCollection<Users> _users;
    
            public UserVM()
            {
                _users = new ObservableCollection<Users>();
                GetUsersAsync();
            }
    
            public void GetUsersAsync()
            {
     
                var query = context.Users1;
                DataServiceQuery<Users> dsq = (DataServiceQuery<Users>)query;
                dsq.BeginExecute(new AsyncCallback(OnGetUsersComplete), dsq);
            }
    
            private void OnGetUsersComplete(IAsyncResult result)
            {
                DataServiceQuery<Users> query = (DataServiceQuery<Users>)result.AsyncState;
                List<Users> list = query.EndExecute(result).ToList();
    
                foreach (Users item in list)
                {
                    item.PropertyChanged += item_PropertyChanged;  
                    _users.Add(item);  //Add row items to collection
                }
            }
    
            void item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                Users usr = (Users)sender;
                context.UpdateObject(usr);
            }
    
            public ObservableCollection<Users> Users1
            {
                get
                {
                    return _users;
                }
            }
        }
    }

     

     

    Tuesday, November 16, 2010 2:39 PM
  • Tag it with [WebGet]

    [WebGet]
    //       
    [WebMethod]
           
    public IQueryable<GetUser_Result> GetUser(string CaseSense, string UserName)
           
    {
                   
    return this.CurrentDataSource.GetUser(CaseSense, UserName).AsQueryable();
               
    // return this.CurrentDataSource.GetUser.Where(o => o.UserName == UserName);
           
    }

    Tuesday, November 16, 2010 4:18 PM
  • Sorry, should've commented that out.  I was trying different things, but I'm currently using the [WebGet] tag with the same "still not hitting it" result. 

    Tuesday, November 16, 2010 4:23 PM
  • It's hard to read your code. Seems you didn't use Load method.

    For query functions, you should use Load method to load them:

    DataServiceCollection<User> UserList = new DataServiceCollection<User>();

    UserList.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(LoadCompleted);

    var query = Context.CreateQuery<User>("GetUser").AddQueryOption("CaseSense", YourCaseSense).AddQueryOption("UserName", YourNameName);

    UserList.LoadAsync(query);


    void LoadCompleted(object sender, LoadCompletedEventArgs e)
    {
                if (e.Error != null)
                {              
                    ErrorWindow.Create(e.Error);                                           
                }

                else  // UserList should be filled now

               {       

               }

    }


    See this thread for more on how to consume WCF data service in Silverlight:

    http://betaforums.silverlight.net/forums/t/208481.aspx

    Tuesday, November 16, 2010 4:34 PM
  • O.K, now it's going into the [WebGet] portion of the service....that part is solved adding in your mentioned few lines of code.  There seems to be no data being returned however??? It foes through the motions and debugging through, it goes to the designer code portion and just ends after getting the first value "UserID", instead of continuing on with loading the other complex types of the sproc (username, firstname, lastname, etc).??

    using System;
    using BAHelloWorld.wcfDStry;
    using System.Collections.ObjectModel;
    using System.Data.Services.Client;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace BAHelloWorld.ViewModel
    {
        public class UserVM : ViewModelBase
        {
            ObservableCollection<Users> _users;
            
            public UserVM()
            {
                _users = new ObservableCollection<Users>();
                GetUsersAsync();
            }
    
            public void GetUsersAsync()
            {
                DataServiceCollection<Users> UserList = new DataServiceCollection<Users>();
                UserList.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(LoadCompleted);
                 string UserName = "'erton'";
            string CaseSense = "'N'";
            var query = context.CreateQuery<Users>("GetUser").AddQueryOption("CaseSense", CaseSense).AddQueryOption("UserName", UserName);
                UserList.LoadAsync(query);
                //var query = context.Users1;
                //DataServiceQuery<Users> dsq = (DataServiceQuery<Users>)query;
                //dsq.BeginExecute(new AsyncCallback(OnGetUsersComplete), dsq);
            }
    
            void LoadCompleted(object sender, LoadCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    //ErrorWindow.Create(e.Error);
                }
                else  // UserList should be filled now
                {
                  
                }
    
            }
    
    
            private void OnGetUsersComplete(IAsyncResult result)
            {
                DataServiceQuery<Users> query = (DataServiceQuery<Users>)result.AsyncState;
                List<Users> list = query.EndExecute(result).ToList();
    
                foreach (Users item in list)
                {
                    item.PropertyChanged += item_PropertyChanged;  //Adding propertyChanged attribute to all row items
                  
    
                    _users.Add(item);  //Add row items to collection
                }
            }
    
            void item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                Users usr = (Users)sender;
                context.UpdateObject(usr);
            }
    
            public ObservableCollection<Users> Users1
            {
                get
                {
                    return _users;
                }
            }
        }
    }


     

     public partial class GetUser_Result : ComplexObject
        {
            #region Factory Method
        
            /// <summary>
            /// Create a new GetUser_Result object.
            /// </summary>
            /// <param name="userID">Initial value of the UserID property.</param>
            /// <param name="userName">Initial value of the UserName property.</param>
            /// <param name="firstName">Initial value of the FirstName property.</param>
            /// <param name="lastName">Initial value of the LastName property.</param>
            /// <param name="role">Initial value of the Role property.</param>
            public static GetUser_Result CreateGetUser_Result(global::System.Int32 userID, global::System.String userName, global::System.String firstName, global::System.String lastName, global::System.String role)
            {
                GetUser_Result getUser_Result = new GetUser_Result();
                getUser_Result.UserID = userID;
                getUser_Result.UserName = userName;
                getUser_Result.FirstName = firstName;
                getUser_Result.LastName = lastName;
                getUser_Result.Role = role;
                return getUser_Result;
            }
    
            #endregion
            #region Primitive Properties
        
            /// <summary>
            /// No Metadata Documentation available.
            /// </summary>
            [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
            [DataMemberAttribute()]
            public global::System.Int32 UserID
            {
                get
                {
                    return _UserID;
                }
                set
                {
                    OnUserIDChanging(value);
                    ReportPropertyChanging("UserID");
                    _UserID = StructuralObject.SetValidValue(value);
                    ReportPropertyChanged("UserID");
                    OnUserIDChanged();
                }
            }
            private global::System.Int32 _UserID;
            partial void OnUserIDChanging(global::System.Int32 value);
            partial void OnUserIDChanged();


     

    Tuesday, November 16, 2010 6:28 PM
  • You don't need this function anymore when you use my code.

    private void OnGetUsersComplete(IAsyncResult result)
            {
                DataServiceQuery<Users> query = (DataServiceQuery<Users>)result.AsyncState;
                List<Users> list = query.EndExecute(result).ToList();

                foreach (Users item in list)
                {
                    item.PropertyChanged += item_PropertyChanged;  //Adding propertyChanged attribute to all row items
                 

                    _users.Add(item);  //Add row items to collection
                }
            }

    public class UserVM : ViewModelBase
    {
             // ObservableCollection<Users> _users; //You don't need to fill this

             DataServiceCollection<Users> UserList {get; private set;} // You can set binding directly to this UserList
             public UserVM()
            {

              UserList = new DataServiceCollection<Users>();
               UserList.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(LoadCompleted);
            }

           public void GetUsersAsync()
           {
              // DataServiceCollection<Users> UserList = new DataServiceCollection<Users>();
              // UserList.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(LoadCompleted);
              string UserName = "'erton'";
              string CaseSense = "'N'";
               var query = context.CreateQuery<Users>("GetUser").AddQueryOption("CaseSense", CaseSense).AddQueryOption("UserName", UserName);
                 UserList.LoadAsync(query);
            }
            void LoadCompleted(object sender, LoadCompletedEventArgs e)
           {
               if (e.Error != null)
              {
                   //ErrorWindow.Create(e.Error);
               }
              else // UserList should be filled now
              {
                       //You can put a break point here to check UserList, it should contains result
               }
           }

    ...
    }

    Read the linked thread I gave you. We already talked about this in great detail in that thread.

    Tuesday, November 16, 2010 7:37 PM
  • Sally, I've set my UserVM.cs the way I believe it should be based on what you've provided me and going through that link.  I'm still at a loss though and when I look at my "UserList" (DataServiceCollection) it still shows 0 or nothing being returned???

    using System;
    using System.Collections.ObjectModel;
    using System.Data.Services.Client;
    using System.Collections.Generic;
    using System.Linq;
    using System.ComponentModel;
    using BAHelloWorld.wcfDStry;
    
    namespace BAHelloWorld.ViewModel
    {
        public class UserVM : ViewModelBase
        {
            crv4Entities _context = new crv4Entities(new Uri("wcfDS_reprtsUsers.svc", UriKind.Relative));
           public DataServiceCollection<Users> UserList { get; private set; }
    
           
            Int32 _userid;
            public Int32 UserID
            {
                get{return _userid;}
                set
                {
                    _userid = value;
                    NotifyPropertyChanged("UserID");
                }
              
             }
    
            string _firstName;
            public string FirstName
             {
                get{return _firstName;}
                set
                {
                    _firstName = value;
                    NotifyPropertyChanged("FirstName");
                }
              
             }
    
            string _lastName;
            public string LastName
            {
                get { return _lastName; }
                set
                {
                    _lastName = value;
                    NotifyPropertyChanged("LastName");
                }
    
            }
    
            char _role;
            public char Role
            {
                get { return _role; }
                set
                {
                    _role = value;
                    NotifyPropertyChanged("Role");
                }
    
            }
    
            DateTime _lastLogin;
            public DateTime LastLogin
            {
                get { return _lastLogin; }
                set
                {
                    _lastLogin = value;
                    NotifyPropertyChanged("LastLogin");
                }
    
            }
    
    
            public UserVM()
            {
                
                UserList = new DataServiceCollection<Users>();
               
                UserList.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(LoadCompleted);
                this.PropertyChanged += (s, ea) =>
                    {
                        //if (ea.PropertyName == "UserID")
                        //{
                        //    GetUsersAsync();
                        //    //UserList = ea.Result;
                        //}
                    };
                
                 GetUsersAsync();
            }
    
            public void GetUsersAsync()
            {
                
                
                 string UserName = "'ealton'";
            string CaseSense = "'N'";
            var query = context.CreateQuery<Users>("GetUser").AddQueryOption("UserName", UserName).AddQueryOption("CaseSense", CaseSense);
                UserList.LoadAsync(query);
                
            }
    
            void LoadCompleted(object sender, LoadCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    //ErrorWindow.Create(e.Error);
                }
                else  // UserList should be filled now
                {
                   Int32 mylistcount = UserList.Count;  //count is always 0 and UserList seems to never be holding any data
                }
    
            }
    
         
            void item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                Users usr = (Users)sender;
                context.UpdateObject(usr);
            }
    
            public ObservableCollection<Users> Users1
            {
                get
                {
                    return UserList; 
                }
            }
        }
    }


     

    Wednesday, November 17, 2010 12:43 PM
  • Test your service first to see if any data returned:

    Make your Service.svc as start up page. Hit f5 to run. You should see all the available entities listed on the page. Change the URL to your function URL:

    http://localhost:***/YourService.svc/GetUser?CaseSense=XXX&UserName=YYY

    If you have data returned from this service call, you should see them on the page. If not, put a break point at your GetUser function to see what is going on.



    Wednesday, November 17, 2010 2:17 PM
  • Yes, It's pulling the data and displaying it in the service when I run it.  Stepping through my code when it hits the "LoadCompleted" section

     if (e.Error != null)
                {
                    ErrorWindow.Create(e.Error);
                }
                else  // UserList should be filled now
                {
                   Int32 mylistcount = UserList.Count;
                }

    I hover over the event arg "e" and I see it's throwing one exception saying: e.QueryOperationResponse.TotalCount threw an {System.SystemException} = {System.InvalidOperationException: The XmlReader must be on a node of type Element instead of a node of type None.
       at System.Xml.Linq.XElement.Load(XmlReader reader, LoadOptions options)
       at System.Xml.Linq.XElement.Load(XmlReader reader)
       at Syst...

    The e.Error value is still null however and doesn't enter the IF porition of code.

      <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
    - <GetUser xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">
    - <element p2:type="crv4Model.GetUser_Result" xmlns:p2="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
      <UserID p2:type="Edm.Int32">5004</UserID> 
      <UserName>ealton</UserName> 
      <FirstName>Ed</FirstName> 
      <LastName>Alton</LastName> 
      <Role>E</Role> 
      <LastLogin p2:type="Edm.DateTime">2010-11-09T15:18:22.227</LastLogin> 
      </element>
      </GetUser>


     

     

    Wednesday, November 17, 2010 2:30 PM
  • 1)

    void LoadCompleted(object sender, LoadCompletedEventArgs e)
           
    {
               
    if (e.Error != null)
               
    {
    //I saw you have this line turned off.
                   
    MessageBox.Show(e.Error.Message); // Alwasy check error before you access returned data.
               
    }
               
    else  // UserList should be filled now
               
    {
                   
    Int32 mylistcount = UserList.Count;  //count is always 0 and UserList seems to never be holding any data
               
    }

           
    }
    2) How many rows are returned. I have no idea why you would get XmlReader error. You might have to change some config settings in your Service:

    public static void InitializeService(DataServiceConfiguration config)
            {
                // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
                // Examples:
                config.SetEntitySetAccessRule("*", EntitySetRights.All);           
                config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);

                config.MaxResultsPerCollection = XXX; //Test with each config setting

                ...
                config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
            }


    This is a good example on how to use WCF dataService in Silverlight:

    http://msdn.microsoft.com/en-us/magazine/ee336128.aspx

    If still get error, post quesions on the WCF DataService forum.


    Wednesday, November 17, 2010 4:07 PM
  • sladapter I appreciate you trying to help with this and I have since uncommented that e.Error.Message line, set the MaxResults to return 1 (which it should be doing anyways) and even changed something I "think" was an issue with the following as it was referencing Users1 (the table) instead of GetUser (the stored procedure).....all still returns 0 rows!  :( 

    public ObservableCollection<Users> GetUser //Users1
            {
                get
                {
                    return UserList; // _users;
                }
            }


     

    I will however go and post over there and see what happens...thanks again for your time and suggestions. 

    UPDATE:On the other site if anyone is following this thread it seems there isn't support for Stored Procecdures with complex types. 

    Wednesday, November 17, 2010 5:22 PM
  • Put this function in your service code, put a break point there to inspect the exception:

    protected override void HandleException(HandleExceptionArgs e)
            {
                try
                {
                    e.UseVerboseErrors = true;
                    base.HandleException(e);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }      


    Wednesday, November 17, 2010 8:24 PM
  • sladapter, I dropped that code in to my wcfDS_reprtsUsers.svc.cs code, but it doesn't fall into or trigger it.  Have you managed to return data from a stored procedure with complex types returning more than one column of data?

    Friday, November 19, 2010 9:00 AM
  • I have never tried with SP, but if you can return data in your Service when you tested your Service code, I don't see how you can't return them to Silverlight no matter where the data come from, unless I'm wrong. Did you ask this question at the WCF DataService forum?

    Check the generated Reference.cs under your Service to see how the User object is generated in this file.

    I'll try to use a stored procedure later when I have more time.



     

    Friday, November 19, 2010 9:37 AM
  • sladapter, I dropped that code in to my wcfDS_reprtsUsers.svc.cs code, but it doesn't fall into or trigger it.  Have you managed to return data from a stored procedure with complex types returning more than one column of data?

    I just tried this case. Yes, I can confirm what you saw. If I map a StoredProcedure result to a ComplexType, no data from WCF data service would return to Silverlight. Actually the Load call would fail because there is no Key attribute tagged for the Complex Type in the generated code. I had to manually add the key tag in the generated code in order for the call to pass through.

        [global::System.Data.Services.Common.DataServiceKeyAttribute("id")]
        public partial class GetTest_Result : global::System.ComponentModel.INotifyPropertyChanged
        {...

        }

    Even the call can pass through, still no data returned in the collection.

    But if I map the StoredProcedure result to the corresponding table (entity type), everything works fine.

    I don't know if you can map your SP result to the User table or not. If you can, it should solve this problem.

    I guess the problem is with the built-in DataService de-serializer. If you do not rely on the DataService de-serializer, you can get the Xml data back by using WebClient:

    WebClient wc = new WebClient();
    wc.DownloadStringCompleted += (s, e) =>
    {
        string xml = e.Result; // you can de-serialize it yourself
    };
    wc.DownloadStringAsync(new Uri(Application.Current.Host.Source, "../YourService.svc/GetUser?CaseSense=XXX&UserName=YYY"));



    Sunday, November 21, 2010 10:34 PM
  • sladapter, thanks for your solution here and time looking into this I appreciate it and I'm sure anyone else following this thread will as well.

      I'll look into the mapping today.  I did have two quick questions on this however (the first I'm sure I'll find out shortly).  If I map to the table (insert, delete, etc) and since I want this to be only a "read" service will that create any issues when I'm setting the AccessRule in the service to "Read" only (I'm thinking not, but figured I'd ask)?

    Lastly, and based on a previous thread I created about using Ria or wcf dataservices.  I was going to say Ria would probably be the way to go using sprocs with complex types over wcf data services.....but, if your code works (and I have all the confidence in the world it will ;) ) then I guess it is just a preference in which to use in this case??

    Monday, November 22, 2010 9:09 AM
  • I'll look into the mapping today.  I did have two quick questions on this however (the first I'm sure I'll find out shortly).  If I map to the table (insert, delete, etc) and since I want this to be only a "read" service will that create any issues when I'm setting the AccessRule in the service to "Read" only (I'm thinking not, but figured I'd ask)?

    You don't need to map insert/delete/update SP if you don't need them. On the EF Designer, right click to select Add/Function Import. Select your SP, Give it a name, then select Entities (User) as Return Collection Type. Change your Service function to use this function. Then you are done.

    If you only need read only data, yes, using WCF DataService might be enough.  



    Monday, November 22, 2010 9:37 AM