Casting ContentType to a ContentPart not working

Topics: Troubleshooting
Mar 16, 2015 at 4:39 PM
Hi,

I have a content part (record) and type described in migration as below:
  public int Create() 
        {
            // Creating table SubscriberPartRecord
            SchemaBuilder.CreateTable("SubscriberPartRecord", table => table
                .ContentPartRecord()
                .Column("FirstName", DbType.String)
                .Column("LastName", DbType.String)
            );

            ContentDefinitionManager.AlterPartDefinition("SubscriberPart", part => part.Attachable(false));

            ContentDefinitionManager.AlterTypeDefinition("Subscriber", type => type
                .WithPart("SubscriberPart")
                .WithPart("UserPart"));
                // DO NOT Attach CommonPart when UserPart is attached - it will create problems

            return 1;
        }
Now in my Subscriber Service, I have the following code:
 public Models.SubscriberPart CreateSubscriber(string email, string password)
        {
            // Create a new instance of type "Subscriber"
            var subscriber = _orchardServices.ContentManager.New("Subscriber");

            // A Subscriber content type is made up of UserPart and SubscriberPart

            // Cast the subscriber to a UserPart
            var userPart = subscriber.As<UserPart>();

            // Cast the subscriber to a SubscriberPart
            var subscriberPart = subscriber.As<SubscriberPart>();

            // I GET A NULL HERE for subscriberPart


            // Set requried userPart fields
            userPart.UserName = email;
            userPart.Email = email;
            userPart.NormalizedUserName = email.ToLowerInvariant();
            userPart.Record.HashAlgorithm = "SHA1";
            userPart.Record.RegistrationStatus = UserStatus.Approved;
            userPart.Record.EmailStatus = UserStatus.Approved;

            // Use orchard's membership service to set the password for the new user
            _membershipService.SetPassword(userPart, password);

            // Store the new subscriber into the database
            _orchardServices.ContentManager.Create(subscriber);

            return subscriberPart;
        }
So when casting from Subscriber Type to Subscriber Part, I get a null. I don't know why this is happening. The log file shows the latest error as below:
2015-03-16 09:58:41,808 [8] Orchard.Exceptions.DefaultExceptionPolicy - Default - An unexpected exception was caught
 http://localhost:30321/OrchardLocal/Arjun.Subscriber/Events/Signup
System.NullReferenceException: Object reference not set to an instance of an object.
   at Orchard.Users.Services.MembershipService.SetPasswordHashed(UserPart userPart, String password)
   at Orchard.Users.Services.MembershipService.SetPassword(IUser user, String password)
   at Arjun.Subscriber.Services.SubscriberService.CreateSubscriber(String email, String password) in c:\myaspfiles\orchard\example1\src\Orchard.Web\Modules\Arjun.Subscriber\Services\SubscriberService.cs:line 47
   at Arjun.Subscriber.Controllers.EventsController.Signup(SignupViewModel signup) in c:\myaspfiles\orchard\example1\src\Orchard.Web\Modules\Arjun.Subscriber\Controllers\EventsController.cs:line 71
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41()
Can anyone see what is going on? i'm not able to figure out the "null" return part. Any suggestions are appreciated. Thanks.
Mar 16, 2015 at 5:18 PM
Edited Mar 16, 2015 at 5:21 PM
Update:

The problem shown in log above is now changed.
 userPart.Record.HashAlgorithm = "SHA1";

 // is updated to

  userPart.HashAlgorithm = "SHA1";
  // This works fine and will not cause MembershipService.SetPasswordHashed() error as shown by log before
Thus,
Orchard.Users.Services.MembershipService.SetPasswordHashed(UserPart userPart, String password)
is not the problem anymore. However, the subscriberPart is null. When this is returned at the end of the function to be used by controller, I get a null exception when I try to access subscriber.Property where subscriber was returned from SubscriberService which equals null.

Hence, now the final problem is the null value of: var subscriberPart = subscriber.As<SubscriberPart>();

And no log entries are shown as the log will contain a controller exception, not the service one.

Thanks.
Mar 16, 2015 at 8:54 PM
Edited Mar 16, 2015 at 8:56 PM
Solved:

There were 2 issues. If a ContentPart does not have a driver method (for example if you are creating and displaying the type using controllers), we need to add an ActivatingFilter<T> for the content part in question.

Help link:
http://stackoverflow.com/questions/10264089/create-content-error-specified-cast-is-not-valid

In my code, I had to make the following changes:
 public class SubscriberPartHandler : ContentHandler
    {
        public SubscriberPartHandler(IRepository<SubscriberPartRecord> repository)
        {
            Filters.Add(StorageFilter.For(repository));

            // Since the UserPart has no driver, we need to add an ActivatingFilter<T> for UserPart which is attached to Subscriber ContentType
            Filters.Add(new ActivatingFilter<UserPart>("Subscriber"));

            // Since the SubscriberPart has no driver, we need to add an ActivatingFilter<T> for SubscriberPart which is attached to Subscriber ContentType
            Filters.Add(new ActivatingFilter<SubscriberPart>("Subscriber")); 
        }
    }
Marked as answer by robroysd on 3/16/2015 at 12:56 PM