This is interesting. Can you check what identity you have when inheriting from JobBase and when not?
HttpContext.Current.User.Identity.Name
Thread.CurrentPrincipal.Identity.Name
Also which membership providers are you using (paste fragment from web.config)?
Hi, this is the fragments from the webconfig.
<roleManager enabled="true" defaultProvider="MultiplexingRoleProvider" cacheRolesInCookie="true">
<providers>
<clear/>
<add name="MultiplexingRoleProvider" type="EPiServer.Security.MultiplexingRoleProvider, EPiServer.Framework" provider1="SqlServerRoleProvider" provider2="WindowsRoleProvider" providerMap1="SqlServerMembershipProvider" providerMap2="WindowsMembershipProvider"/>
<add name="WindowsRoleProvider" applicationName="EPiServerSample" type="EPiServer.Security.WindowsRoleProvider, EPiServer"/>
<add name="SqlServerRoleProvider" connectionStringName="EPiServerDB" applicationName="EPiServerSample" type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<add name="EPiServerCommonRoleProvider" applicationName="EPiServerCommonApplication" type="EPiServer.Common.Web.Authorization.RoleProvider, EPiServer.Common.Web.Authorization"/>
<!-- ECF Start -->
<add connectionStringName="EcfSqlConnection" applicationName="rcog-shop-uat" name="CMSRoleProvider" type="Mediachase.Commerce.Customers.Profile.Providers.CustomerSqlRoleProvider, Mediachase.Commerce"/>
<!-- ECF End -->
</providers>
</roleManager>
<membership defaultProvider="MultiplexingMembershipProvider" userIsOnlineTimeWindow="10" hashAlgorithmType="HMACSHA512">
<providers>
<clear/>
<add name="MultiplexingMembershipProvider" type="EPiServer.Security.MultiplexingMembershipProvider, EPiServer.Framework" provider1="SqlServerMembershipProvider" provider2="WindowsMembershipProvider"/>
<add name="WindowsMembershipProvider" type="EPiServer.Security.WindowsMembershipProvider, EPiServer" deletePrefix="BUILTIN\" searchByEmail="true"/>
<add name="SqlServerMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="EPiServerDB" requiresQuestionAndAnswer="false" applicationName="EPiServerSample" requiresUniqueEmail="true" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>
<add name="EPiServerCommonMembershipProvider" applicationName="EPiServerCommonApplication" type="EPiServer.Common.Web.Authorization.MembershipProvider, EPiServer.Common.Web.Authorization"/>
<!-- ECF Start -->
<add connectionStringName="EcfSqlConnection" applicationName="rcog-shop-uat" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed" passwordStrengthRegularExpression="" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" name="CMSMembershipProvider" type="Mediachase.Commerce.Customers.Profile.Providers.CustomerSqlMembershipProvider, Mediachase.Commerce"/>
<!-- ECF End -->
</providers>
</membership>
I'll find out the identity when I can debug the code.
Thanks for your help
If the job is run automaticly the HttpContext.Current is null. And the Thread.CurrentPrincipal.Identity.Name should be the service account. Don't think this have anything to do with JobBase. Ths is working as intended :(
Hi,
Thanks. What Im doing is a manual Job that imports users from an external source. As each user comes into the system i am setting up Membership roles etc. Is this something that is possible using the JobBase?
Thanks
Hi Anders,
When you say that this is working as intended do you mean that we have a fault with our code and that the Membership should work as it does without the JobBase or do you mean that the Membership should NOT work when we Inherit JobBase?
As I rember the JobBase creates a thread, and executes the the thread. It will start to construct a object from your class. That should be done in the current thread.. So try to make a reference to your user in the constructor.
the code that is run in ScheduledJob is
private void InternalExec(bool startThread)
{
try
{
Type type = Assembly.Load(this.AssemblyName).GetType(this.TypeName);
if (type.IsSubclassOf(typeof(JobBase)))
{
lock (ScheduledJob._syncRoot)
{
if (ScheduledJob._runningJobs.ContainsKey(this.ID))
{
return;
}
}
Thread thread = new Thread(delegate
{
Timer isAliveTimer = null;
JobBase jobBase = null;
try
{
jobBase = (JobBase)Activator.CreateInstance(type);
jobBase.ScheduledJobId = this.ID;
lock (ScheduledJob._syncRoot)
{
ScheduledJob._runningJobs.Add(this.ID, jobBase);
}
jobBase.StatusChanged += new EventHandler<JobStatusChangedEventArgs>(this.job_StatusChanged);
this._internalRunning = true;
this.PingDatabaseWithRunningState(this.ID);
isAliveTimer = new Timer(new TimerCallback(this.PingDatabaseWithRunningState), jobBase.ScheduledJobId, this._pingTime, this._pingTime);
string text = jobBase.Execute();
ScheduledJob.DataAccess.Service().ReportExecuteItem(jobBase.ScheduledJobId, 0, text);
}
catch (Exception exception2)
{
ScheduledJob.log.Error(string.Format("Job {0} failed", this.TypeName), exception2);
ScheduledJob.ReportError(this.ID, exception2);
}
finally
{
lock (ScheduledJob._syncRoot)
{
ScheduledJob._runningJobs.Remove(this.ID);
}
if (jobBase != null)
{
jobBase.StatusChanged -= new EventHandler<JobStatusChangedEventArgs>(this.job_StatusChanged);
}
this._internalRunning = false;
isAliveTimer = this.CleanupTimer(isAliveTimer);
ScheduledJob.DataAccess.Service().UpdateRunningState(this.ID, this._internalRunning);
}
});
thread.Start();
}
else
{
if (startThread)
{
Thread thread2 = new Thread(delegate
{
this.ExecuteStaticMethod(type);
});
thread2.Start();
}
else
{
this.ExecuteStaticMethod(type);
}
}
}
catch (FileNotFoundException exception)
{
ScheduledJob.log.Error(string.Format("Failed to load assembly '{0}' to remove this job permanent remove the contents of tblScheduledItemLog and tblScheduledItem for the job with jobId ='{1}' from the database", this.AssemblyName, this.ID), exception);
ScheduledJob.ReportError(this.ID, exception);
}
catch (Exception ex)
{
ScheduledJob.log.Error(string.Format("3.1.2 Failed to execute job {0}", this.ID), (ex.InnerException != null) ? ex.InnerException : ex);
ScheduledJob.ReportError(this.ID, ex);
}
}
Some more details on your use case would be great - "... As each user comes into the system i am setting up Membership roles etc. Is this something that is possible using the JobBase?".
Scheduled jobs behave differently around current user identity when executed manually or automatically - but I'm not quite sure that you need current user.
If he has a job that only should be done manually I can se the reason for needing to log who startet the job.....
Anders: As of 7.5 the job runs inside of the app pool (scheduler service removed). So I would assume that when running the job automatically the HttpContext.Current is not null and the current user is the app pool user.
Mari: The same code is run as far as I can tell. So it's inside a thread, and I think the HttpContext.Current is nulll there
This is a callstack before your job's Execute method is called:
> YourJob.Import.Execute() Line 46 C#
EPiServer.dll!EPiServer.DataAbstraction.ScheduledJob.InternalExec.AnonymousMethod__5() Unknown
mscorlib.dll!System.Threading.Tasks.Task.Execute() Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) Unknown
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) Unknown
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Unknown
[Native to Managed Transition]
HttpContext is not surviving thread. It just goes on holidays then..
But the easy soulution is to make a reference to it in the constructor....
public class Test:JobBase
{
string UserName="";
public Test()
{
UserName=HttpContext.Current.User.Identity.Name;
}
}
My point is that you can make a reference to the System.Web.Security.Membership there instead of the name of the current user
How do you make a reference to System.Web.Security.Membership in a constructor?
Andres: as type construction happens already in Thread start lambda - HttpContext is null there as well.
HI, Thanks for all your imput - so, to summarize, is this possible to do or not?
Thanks again
Unfortunately with all the side discussions I'm lost with proper task you need to accomplish :) Do you need to create a user during manual job execution, do you need to get access to current user executing job manually, or something else?
:)
What we have written is a Scheduled job that imports users from an external source. As we loop through each record we create / update a Commerce User and create/update a CMS User (member) which sets up their Roles etc. This worked well but as there are over 4,000 users we wanted to include JobBase to write a Progress message on screen together with a Stop button. But since Inheriting JobBase the Membership Create User / GetUser doesnt work any more - it is throwing an Object Reference is not set to an Instance of an object Error.
Can you post exact stack trace and failing location? Wondering what and where excatly is failing. Difference between inheriting from JobBase and not is just telling EPiServer to monitor StatusChanged event..
Hi, thanks for your help.
It fails on the CreateUser / getUser but we will have to leave this for now as we have run out of time.
Thanks again
Hi,
We are using System.Web.Security.Membership.GetUser(); in a Scheduled Job task but since inheriting JobBase to get the Progress of the Job the Membership is returning Null - without inheriting JobBase it works well.
PS we are not using MVC.
Thanks
Jon