The error being the MS ‘ExecuteNonQuery requires an open and available Connection. The connection’s current state is closed.’
I am using servicestack RepositoryBase for all my Repos. If I comment out the async and just do insert ids into list then the Db.UpdateOnly works so perhaps there is some kind of synchronization context issue, however I would have thought that the MessageRepo object would then just be null rather than no longer managing to establish a connection (it previously did manage in the same method).
Cut down code below:
public class MessageRepo : RepositoryBase
{
//THIS WORKS!!!
public List<UserMessage> GetUserMessagesThatNeedToBeSent()
{
var messages = Db.Select<UserMessage>(q => q.Finalised && !q.HasBeenSent);
return messages;
}
//This Complains that connection is not open.
public void MarkAsSent(long[] ids)
{
if (ids.Length > 0)
{
Db.UpdateOnly(
new UserMessage { HasBeenSent = true },
onlyFields: p => new { p.HasBeenSent },
where: p => Sql.In(p.Id, ids)
);
}
}
}
public class ConsoleProgramToProcessPendingMessages
{
static void Main()
{
using (var appHost = new ProcessPendingMessagesAppHost())
{
LogManager.LogFactory = new ConsoleLogFactory();
appHost.Init();
var userMessageProcessor = new UserMessageProcessor();
userMessageProcessor.ProcessPendingMessagesAsync().GetAwaiter().GetResult();
}
}
}
internal class ProcessPendingMessagesAppHost : ServiceStackHost
{
public ProcessPendingMessagesAppHost() : base("EE.ProcessPendingMessages", typeof(ProcessPendingMessagesAppHost).Assembly) { }
public override void Configure(Container container)
{
var connectionString = ConfigUtils.GetConnectionString("AppDb");
container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(connectionString, SqlServer2012Dialect.Provider));
container.RegisterAutoWired<MessageRepo>().ReusedWithin(ReuseScope.None);
}
}
public class Emailer
{
private async Task<bool> SomeMethodThatReturnsTrueAsync()
{
return true;
}
public async Task<bool> SendUserMessageAsync(string userMessageText)
{
return await SomeMethodThatReturnsTrueAsync();
}
}
public class UserMessageProcessor
{
protected static readonly ILog Log = LogManager.GetLogger(typeof(ActionsEmailer));
public MessageRepo MessageRepo { get; set; }
private readonly string _callbackBaseUrl;
public UserMessageProcessor()
{
HostContext.Container.AutoWire(this);
var appSettings = new AppSettings();
_callbackBaseUrl = appSettings.Get("EmailCallbackBaseUrl");
}
public async Task ProcessPendingMessagesAsync()
{
try
{
var messages = MessageRepo.GetUserMessagesThatNeedToBeSent();
if (messages.Count > 0)
{
var idsOfThoseSentOk = new List<long>();
var emailer = new Emailer();
Log.InfoFormat("...Start message loop");
foreach (var message in messages)
{
//commenting out the await stuff makes it work.
if (await emailer.SendUserMessageAsync(message.Text).ConfigureAwait(true))
{
idsOfThoseSentOk.Add(message.Id);
}
}
MessageRepo.MarkAsSent(idsOfThoseSentOk.ToArray());
}
else
{
Log.Info("No messages to process.");
}
}
catch (Exception ex)
{
Log.Error(ex);
throw;
}
}
}