Skip to content

Instantly share code, notes, and snippets.

@Rockerby
Last active February 6, 2025 23:55
Show Gist options
  • Save Rockerby/666b3e0e52a78f503355a88f055c040b to your computer and use it in GitHub Desktop.
Save Rockerby/666b3e0e52a78f503355a88f055c040b to your computer and use it in GitHub Desktop.
This is a fix for an error that occurs in Umbraco v8.X when using SQL 2019+ in some instances. It fixes the error "versionDate is not a column name" in the back office. Check out https://our.umbraco.com/forum/using-umbraco-and-getting-started/102016-column-ordering-in-members-listview-error
/*
This file is just a copy of the core MemberService but we can't just overwrite the function we need
so we need to use it as a wrapper to the actual MemberService; the baseService defined below.
*/
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Helpers;
using System.Web.Security;
using System.Web.UI.WebControls;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Scoping;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Web.Models.ContentEditing;
namespace MyNamespace
{
public class BespokeMemberService : ScopeRepositoryService, IMemberService
{
private readonly IMemberRepository _memberRepository;
private readonly IMemberTypeRepository _memberTypeRepository;
private readonly IMemberGroupRepository _memberGroupRepository;
private readonly IAuditRepository _auditRepository;
private readonly IMemberGroupService _memberGroupService;
private readonly IMediaFileSystem _mediaFileSystem;
private readonly MemberService baseService;
//only for unit tests!
internal MembershipProviderBase MembershipProvider { get; set; }
#region Constructor
public BespokeMemberService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService, IMediaFileSystem mediaFileSystem,
IMemberRepository memberRepository, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, IAuditRepository auditRepository)
: base(provider, logger, eventMessagesFactory)
{
_memberRepository = memberRepository;
_memberTypeRepository = memberTypeRepository;
_memberGroupRepository = memberGroupRepository;
_auditRepository = auditRepository;
_memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService));
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
baseService = new MemberService(provider, logger, eventMessagesFactory, memberGroupService, mediaFileSystem,
memberRepository, memberTypeRepository, memberGroupRepository, auditRepository);
}
#endregion
#region Count
public int GetCount(MemberCountType countType)
{
return baseService.GetCount(countType);
}
public int Count(string memberTypeAlias = null)
{
return baseService.Count(memberTypeAlias);
}
#endregion
#region Create
public IMember CreateMember(string username, string email, string name, string memberTypeAlias)
{
return baseService.CreateMember(username, email, name, memberTypeAlias);
}
public IMember CreateMember(string username, string email, string name, IMemberType memberType)
{
return baseService.CreateMember(username, email, name, memberType);
}
IMember IMembershipMemberService<IMember>.CreateWithIdentity(string username, string email, string passwordValue, string memberTypeAlias)
{
return CreateMemberWithIdentity(username, email, passwordValue, memberTypeAlias);
}
IMember IMembershipMemberService<IMember>.CreateWithIdentity(string username, string email, string passwordValue, string memberTypeAlias, bool isApproved)
{
return CreateMemberWithIdentity(username, email, username, passwordValue, memberTypeAlias, isApproved);
}
public IMember CreateMemberWithIdentity(string username, string email, string memberTypeAlias)
{
return baseService.CreateMemberWithIdentity(username, email, memberTypeAlias);
}
public IMember CreateMemberWithIdentity(string username, string email, string memberTypeAlias, bool isApproved)
{
return baseService.CreateMemberWithIdentity(username, email, memberTypeAlias, isApproved);
}
public IMember CreateMemberWithIdentity(string username, string email, string name, string memberTypeAlias)
{
return baseService.CreateMemberWithIdentity(username, email, name, memberTypeAlias);
}
public IMember CreateMemberWithIdentity(string username, string email, string name, string memberTypeAlias, bool isApproved)
{
return baseService.CreateMemberWithIdentity(username, email, name, memberTypeAlias, isApproved);
}
public IMember CreateMemberWithIdentity(string username, string email, string name, string passwordValue, string memberTypeAlias, bool isApproved = true)
{
return baseService.CreateMemberWithIdentity(username, email, name, passwordValue, memberTypeAlias, isApproved);
}
public IMember CreateMemberWithIdentity(string username, string email, IMemberType memberType)
{
return baseService.CreateMemberWithIdentity(username, email, memberType);
}
public IMember CreateMemberWithIdentity(string username, string email, IMemberType memberType, bool isApproved)
{
return baseService.CreateMemberWithIdentity(username, email, memberType, isApproved);
}
public IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType)
{
return baseService.CreateMemberWithIdentity(username, email, name, memberType);
}
public IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType, bool isApproved)
{
return baseService.CreateMemberWithIdentity(username, email, name, memberType, isApproved);
}
#endregion
#region Get, Has, Is, Exists...
public IMember GetById(int id)
{
return baseService.GetById(id);
}
public IMember GetByKey(Guid id)
{
return baseService.GetByKey(id);
}
public IEnumerable<IMember> GetAll(long pageIndex, int pageSize, out long totalRecords)
{
return baseService.GetAll(pageIndex, pageSize, out totalRecords);
}
public IEnumerable<IMember> GetAll(long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "")
{
return GetAll(pageIndex, pageSize, out totalRecords,
orderBy, orderDirection, memberTypeAlias, filter);
}
public IEnumerable<IMember> GetAll(long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string memberTypeAlias, string filter)
{
// Mess with the order by queries if they are the ones giving us issue
if (orderBy == "updateDate")
{
orderBy = "versionDate";
orderBySystemField = true;
}
else if (orderBy == "createDate")
{
// Created date should be in the same order as the node id, but createDate throws an exception
orderBy = "id";
orderBySystemField = true;
}
return baseService.GetAll(pageIndex, pageSize, out totalRecords,
orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter);
}
public IMember GetByProviderKey(object id)
{
return baseService.GetByProviderKey(id);
}
public IMember GetByEmail(string email)
{
return baseService.GetByEmail(email);
}
public IMember GetByUsername(string username)
{
return baseService.GetByUsername(username);
}
public IEnumerable<IMember> GetMembersByMemberType(string memberTypeAlias)
{
return baseService.GetMembersByMemberType(memberTypeAlias);
}
public IEnumerable<IMember> GetMembersByMemberType(int memberTypeId)
{
return baseService.GetMembersByMemberType(memberTypeId);
}
public IEnumerable<IMember> GetMembersByGroup(string memberGroupName)
{
return baseService.GetMembersByGroup(memberGroupName);
}
public IEnumerable<IMember> GetAllMembers(params int[] ids)
{
return baseService.GetAllMembers(ids);
}
public IEnumerable<IMember> FindMembersByDisplayName(string displayNameToMatch, long pageIndex, int pageSize, out long totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
return baseService.FindMembersByDisplayName(displayNameToMatch, pageIndex, pageSize, out totalRecords, matchType);
}
public IEnumerable<IMember> FindByEmail(string emailStringToMatch, long pageIndex, int pageSize, out long totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
return baseService.FindByEmail(emailStringToMatch, pageIndex, pageSize, out totalRecords, matchType);
}
public IEnumerable<IMember> FindByUsername(string login, long pageIndex, int pageSize, out long totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
return baseService.FindByUsername(login, pageIndex, pageSize, out totalRecords, matchType);
}
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact)
{
return baseService.GetMembersByPropertyValue(propertyTypeAlias, value, matchType);
}
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact)
{
return baseService.GetMembersByPropertyValue(propertyTypeAlias, value, matchType);
}
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, bool value)
{
return baseService.GetMembersByPropertyValue(propertyTypeAlias, value);
}
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact)
{
return baseService.GetMembersByPropertyValue(propertyTypeAlias, value, matchType);
}
public bool Exists(int id)
{
return baseService.Exists(id);
}
public bool Exists(string username)
{
return baseService.Exists(username);
}
#endregion
#region Save
/// <inheritdoc />
public void SetLastLogin(string username, DateTime date)
{
baseService.SetLastLogin(username, date);
}
/// <inheritdoc />
public void Save(IMember member, bool raiseEvents = true)
{
baseService.Save(member, raiseEvents);
}
/// <inheritdoc />
public void Save(IEnumerable<IMember> members, bool raiseEvents = true)
{
baseService.Save(members, raiseEvents);
}
#endregion
#region Delete
public void Delete(IMember member)
{
baseService.Delete(member);
}
#endregion
#region Roles
public void AddRole(string roleName)
{
baseService.AddRole(roleName);
}
public IEnumerable<string> GetAllRoles()
{
return baseService.GetAllRoles();
}
public IEnumerable<string> GetAllRoles(int memberId)
{
return baseService.GetAllRoles(memberId);
}
public IEnumerable<string> GetAllRoles(string username)
{
return baseService.GetAllRoles(username);
}
public IEnumerable<int> GetAllRolesIds()
{
return baseService.GetAllRolesIds();
}
public IEnumerable<int> GetAllRolesIds(int memberId)
{
return baseService.GetAllRolesIds(memberId);
}
public IEnumerable<int> GetAllRolesIds(string username)
{
return baseService.GetAllRolesIds(username);
}
public IEnumerable<IMember> GetMembersInRole(string roleName)
{
return baseService.GetMembersInRole(roleName);
}
public IEnumerable<IMember> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
return baseService.FindMembersInRole(roleName, usernameToMatch, matchType);
}
public bool DeleteRole(string roleName, bool throwIfBeingUsed)
{
return baseService.DeleteRole(roleName, throwIfBeingUsed);
}
public void AssignRole(string username, string roleName)
{
baseService.AssignRole(username, roleName);
}
public void AssignRoles(string[] usernames, string[] roleNames)
{
baseService.AssignRoles(usernames, roleNames);
}
public void DissociateRole(string username, string roleName)
{
baseService.DissociateRole(username, roleName);
}
public void DissociateRoles(string[] usernames, string[] roleNames)
{
baseService.DissociateRoles(usernames, roleNames);
}
public void AssignRole(int memberId, string roleName)
{
baseService.AssignRole(memberId, roleName);
}
public void AssignRoles(int[] memberIds, string[] roleNames)
{
baseService.AssignRoles(memberIds, roleNames);
}
public void DissociateRole(int memberId, string roleName)
{
baseService.DissociateRole(memberId, roleName);
}
public void DissociateRoles(int[] memberIds, string[] roleNames)
{
baseService.DissociateRoles(memberIds, roleNames);
}
#endregion
#region Event Handlers
/// <summary>
/// Occurs before Delete
/// </summary>
public static event TypedEventHandler<IMemberService, DeleteEventArgs<IMember>> Deleting;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IMemberService, DeleteEventArgs<IMember>> Deleted;
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saving;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saved;
/// <summary>
/// Occurs after roles have been assigned.
/// </summary>
public static event TypedEventHandler<IMemberService, RolesEventArgs> AssignedRoles;
/// <summary>
/// Occurs after roles have been removed.
/// </summary>
public static event TypedEventHandler<IMemberService, RolesEventArgs> RemovedRoles;
#endregion
#region Membership
/// <summary>
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
/// </summary>
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
/// Members if they choose to. </remarks>
/// <param name="member">The Member to save the password for</param>
/// <param name="password">The password to encrypt and save</param>
public void SavePassword(IMember member, string password)
{
baseService.SavePassword(member, password);
}
#endregion
#region Content Types
public void DeleteMembersOfType(int memberTypeId)
{
baseService.DeleteMembersOfType(memberTypeId);
}
public string GetDefaultMemberType()
{
return baseService.GetDefaultMemberType();
}
#endregion
}
}
/*
We need to replace the current MemberService implementation with our wrapper class
*/
using Umbraco.Core;
using Umbraco.Core.Composing;
namespace MyNamespace
{
public class DIComposer : IUserComposer
{
public void Compose(Composition composition)
{
// LightInject will overwrite any pre-existing registrations, so we can just set this
composition.RegisterUnique<Umbraco.Core.Services.IMemberService, BespokeMemberService>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment