Search code examples
c#.netbotframeworkbots

Make bot send message every day at specific time


I am building a bot with Bot Framework, that is supposed to run in MS Teams and I want it to send me a message every day at 6:30 in the morning.

I have a method that is called every day at 6:30 inside the Program file. And I have a method that sends a message from the bot.

This is the code for my timer:

private static Timer _timer;

    private static int count = 1;


    public static void Main(string[] args)
    {        
        //Initialization of _timer   
        _timer = new Timer(x => { callTimerMethod(); }, null, Timeout.Infinite, Timeout.Infinite);
        Setup_Timer();

        BuildWebHost(args).Run();
    }

    /// <summary>  
    /// This method will execute every day at 06:30.   
    /// </summary>  
    public static void callTimerMethod()
    {
        System.Diagnostics.Debug.WriteLine(string.Format("Method is called"));
        System.Diagnostics.Debug.Write(DateTime.Now.ToString("dddd, dd MMMM yyyy HH:mm:ss"));
        count = count + 1;
    }

    /// <summary>  
    /// This method will set the timer execution time and will change the   
    /// tick time of timer.
    /// </summary>  
    private static void Setup_Timer()
    {
        DateTime currentTime = DateTime.Now;
        DateTime timerRunningTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 6, 30, 0);
        timerRunningTime = timerRunningTime.AddDays(1);

        double tickTime = (double)(timerRunningTime - DateTime.Now).TotalSeconds;

        _timer.Change(TimeSpan.FromSeconds(tickTime),
        TimeSpan.FromSeconds(tickTime));
    }

And what i want to archive is that I want to change the content of callTimerMethod() to this method:

public async Task AlertSubscribers(ITurnContext turncontext, CancellationToken cancellationToken = default(CancellationToken))
    {
        using (var db = new DataBaseContext())
        {
            var msg = "";
            var today = DateTime.Today.ToString("dddd");
            var product = db linq code;

            foreach(var prod in product)
            {
                msg = $"Reminder! {prod.bla}";
            }

            // Get the conversation state from the turn context.
            var state = await _accessors.CounterState.GetAsync(turncontext, () => new CounterState());

            // Set the property using the accessor.
            await _accessors.CounterState.SetAsync(turncontext, state);

            // Save the new turn count into the conversation state.
            await _accessors.ConversationState.SaveChangesAsync(turncontext);

            // Echo back to the user whatever msg is.
            await turncontext.SendActivityAsync(msg);
        }
    }

But I can't find a way to archive it... Would really appreciate some help, I have searched around a lot but havent found a similar problem.

The problem is all the namespaces (for an example ITurncontext, Conversationstate, and so on...)

Hope that describes my problem...

Thanks in advance!

EDIT:

It doesn't nessessarly need to be the AlertSubscribers() method, but a function och just code that does the similar thing.

I have tried this code but i cant get it to make the bot send a message to the user(in this case me in the Emulator):

public static void callTimerMethod()
    {
        IMessageActivity message = Activity.CreateMessageActivity();

        message.Text = "Hello!";
        message.TextFormat = "plain";
        message.Locale = "en-Us";
        message.ChannelId = "emulator";
        message.Id = "A guid";
        message.InputHint = "acceptingInput";
        message.LocalTimestamp = DateTimeOffset.Now;
        message.ReplyToId = "A guid";
        message.ServiceUrl = "http://localhost:50265";
        message.Timestamp = DateTimeOffset.Now;
        message.Type = "ConversationUpdate";

        message.AsConversationUpdateActivity();
    }

I am new to Bot framework so my code and my thaughts may be wrong...


Solution

  • Solved it!

    public static async void callTimerMethod()
    {
        await ConversationStarter.Resume("conversationId", "emulator");
    }
    

    I had to change the callTimerMethod() to an async method and create a ConversationStarter class that handles the message for me.

    This is ConversationStarter :

    public class ConversationStarter
    {
        public static string fromId;
        public static string fromName;
        public static string toId;
        public static string toName;
        public static string serviceUrl;
        public static string channelId;
        public static string conversationId;
    
    
        public static async Task Resume(string conversationId, string channelId)
        {
            conversationId = await Talk(conversationId, channelId, $"Hi there!");
            conversationId = await Talk(conversationId, channelId, $"This is a notification!");
        }
    
        private static async Task<string> Talk(string conversationId, string channelId, string msg)
        {
            var userAccount = new ChannelAccount(toId, toName);
            var botAccount = new ChannelAccount(fromId, fromName);
            var connector = new ConnectorClient(new Uri(serviceUrl));
    
            IMessageActivity message = Activity.CreateMessageActivity();
            if (!string.IsNullOrEmpty(conversationId) && !string.IsNullOrEmpty(channelId))
            {
                message.ChannelId = channelId;
            }
            else
            {
                conversationId = (await connector.Conversations.CreateDirectConversationAsync(botAccount, userAccount)).Id;
            }
            message.From = botAccount;
            message.Recipient = userAccount;
            message.Conversation = new ConversationAccount(id: conversationId);
            message.Text = msg;
            message.Locale = "en-Us";
            await connector.Conversations.SendToConversationAsync((Activity)message);
            return conversationId;
        }
    
    }