Azure error "Non-static method requires a target." on SaveChanges()

Living on the bleeding edge has more rewards (coding gets easier and easier) than injury but today I had to do a wee bit of bleeding....   Numerous hours spent on my first stab at saving a Person record in the Azure cloud.   It wasn't the "ResourceNotFound" errors that caused the most blood loss, they were contributed to simple mistakes on my part such as configuring DataConnection in the Cloud settings while using DataConnectionString in code and not deriving my Person class from TableServiceEntity.  

It was the obscure "Non-static method requires a target" error after finally getting to a point where I could submit my changes via SaveChanges() that had an artery going --- wasn't sure what it meant or how to stop the bleeding....   Since I just upgraded to Visual Studio 2010 RC (from Beta 2 which resulted in me losing all of my UML diagrams as they are not compatible with RC) I couldn't be totally sure that the problem wasn't associated with the upgrade.

To get past these I found it easiest to locate the most basic lesson I could find in the Azure training package and then ensure it ran successfully, I then proceeded to copy/paste the code into my solution but it didn't resolve this error.

Bing'ing the issue reveal enough information to learn that others have experienced this issue if they have a property that is based on an interface or if it returns null (reflection crashes and burns without much indication why).   Since the MicrosoftVault SDK Person field has deep levels of derived base classes I decided at this stage of the game to go with a new EHRPerson POCO and see if I could successfully save a record.

This solved the problem!   With "Create" nicely out of the way it is time to move on to the other CRUD operations.  The bleeding has stopped (for now)
 

Default.aspx.cs (code behind) 

using System;
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Linq;
using EHREntities.ServiceContext;
using GWN.EHR.Entities;
using Microsoft.WindowsAzure;

namespace GWN.EHR.CloudWebRole
{
 public partial class _Default : System.Web.UI.Page
 {
        CloudStorageAccount account = null;
        PersonDataContext context = null;

        protected void Page_Load(object sender, EventArgs e)
        {
            account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            context = new PersonDataContext(account.TableEndpoint.ToString(), account.Credentials);

            txtID.Text = Guid.NewGuid().ToString();

            GetList();
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            var statusMessage = String.Empty;
            try
            {
                context.AddPerson(new EHRPerson
                {
                    Name = txtName.Text ,
                    ID = txtID.Text,
                    Organization = txtOrganization.Text,
                    PersonType = txtPersonType.Text,
                    ProfessionalTraining = txtTraining.Text,
                });
                GetList();
            }
            catch (DataServiceRequestException ex)
            {
                throw;
            }
        }

        public void GetList()
        {
            lstPersonList.DataSource = context.PersonList.ToList<EHRPerson>();
            lstPersonList.DataBind();
        }
 }
}

EHRPerson.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.StorageClient;

namespace GWN.EHR.Entities
{
    /// <summary>
    ///
    /// </summary>
    public class EHRPerson : TableServiceEntity
    {
        public EHRPerson()
        {
            PartitionKey = "Person";

            // Row key allows sorting, so we make sure the rows come
            // back in time order.
            RowKey = string.Format("{0:10}_{1}",
                DateTime.MaxValue.Ticks - DateTime.Now.Ticks,
                Guid.NewGuid());
        }

        public string ID { get; set; }
        public string Name { get; set; }
        public string Organization { get; set; }
        public string ProfessionalTraining { get; set; }
        public string PersonType { get; set; }

        public override string ToString()
        {
            return string.Format("{0}: {1}, {2}", Name, Organization, ID);
        }
    }
}

PersonDataContext.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.Health.ItemTypes;
using GWN.EHR.Entities;

namespace EHREntities.ServiceContext
{
 public class PersonDataContext : TableServiceContext
 {
       public IQueryable<EHRPerson> PersonList
        {
            get
            {
                return this.CreateQuery<EHRPerson>("PersonList");
            }
        }

       public PersonDataContext(string baseAddress, StorageCredentials credentials)
            : base(baseAddress, credentials)
        {
        }

        public void AddPerson(EHRPerson person)
        {
            this.AddObject("PersonList", person );
            this.SaveChanges();
        }
 }
}

WebRole.cs

using System.Linq;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using EHREntities.ServiceContext;

namespace GWN.EHR.CloudWebRole
{
        public class WebRole : RoleEntryPoint
        {
            public override bool OnStart()
            {
                DiagnosticMonitor.Start("DiagnosticsConnectionString");

                // For information on handling configuration changes
                // see the MSDN topic at
http://go.microsoft.com/fwlink/?LinkId=166357.
                RoleEnvironment.Changing += RoleEnvironmentChanging;

                // This code sets up a handler to update CloudStorageAccount instances when their corresponding
                // configuration settings change in the service configuration file.
                CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
                {
                    // Provide the configSetter with the initial value
                    configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

                    RoleEnvironment.Changed += (anotherSender, arg) =>
                    {
                        if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                            .Any((change) => (change.ConfigurationSettingName == configName)))
                        {
                            // The corresponding configuration setting has changed, propagate the value
                            if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                            {
                                // In this case, the change to the storage account credentials in the
                                // service configuration is significant enough that the role needs to be
                                // recycled in order to use the latest settings. (for example, the
                                // endpoint has changed)
                                RoleEnvironment.RequestRecycle();
                            }
                        }
                    };
                });

                /// Create data table from MessageDataServiceContext
                /// It is recommended the data tables should be only created once. It is typically done as a
                /// provisioning step and rarely in application code.
                var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

                // dynamically create the tables
                CloudTableClient.CreateTablesFromModel(typeof(PersonDataContext),
                                                       account.TableEndpoint.AbsoluteUri, account.Credentials);

                return base.OnStart();
            }

            private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
            {
                // If a configuration setting is changing
                if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
                {
                    // Set e.Cancel to true to restart this role instance
                    e.Cancel = true;
                }
            }
        }
    }
 


Tags: ,
Categories: Azure


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know