Start with the conversation, not the code
A chatbot succeeds or fails on its design. Frameworks, including Microsoft’s Bot Framework, handle the plumbing: receiving messages, tracking conversation state and sending replies. Whether the bot is actually useful depends on decisions you make before opening an editor. This article covers those decisions and keeps the C# at the level of ideas, because exact packages, templates and tooling change and should be checked against the current official documentation.
Decide what the bot is for
A narrow purpose works better than a general one. “Answer opening-hours and booking questions for a workshop” is achievable. “Help customers with anything” is not. Write down the five or ten things users will most often ask for, and decide what the bot should do when asked about anything else. A good conversational chatbot is clear about its limits and hands off gracefully.
The building blocks
Activities and the turn
In this style of framework, everything the user does arrives as an activity: a message, someone joining the chat, a button press. Your bot receives each activity, decides what to do and sends one or more activities back. One exchange is often called a turn. In C# you typically write a class that handles these events, and the framework calls it each time something arrives.
Conversation state
Web requests are independent, but conversations are not. The bot must remember where the user is: which question was asked, which answers have been given. Frameworks provide state storage for this. Think about what you keep, where it is stored and for how long. Stored conversations may contain personal information, so keep only what you need and delete it when you no longer do.
Dialogs
A dialog is a managed piece of conversation, such as “collect a name, then a date, then confirm”. Dialogs can be nested and reused, and they handle awkward real-life behaviour: users answering out of order, changing their minds or abandoning the exchange. Designing these flows on paper first, as a simple diagram, saves a lot of rework. It is the same thinking as the state machines used for device behaviour, with states, transitions and a clear way out.
Intents and entities
To understand free text, bots often use an intent-recognition step. An intent is what the user wants (“book a slot”), and entities are the details inside the message (a date, a place). You can match simple patterns with rules, or use a trained language-understanding service or a language model. Rules are predictable and cheap; trained models handle varied wording better but can misclassify. Whatever you pick, include a fallback for “I did not understand”, with a few suggestions rather than a dead end.
If you use a language model for answers, remember it can invent plausible but false details. The behaviour behind model hallucinations is a good reason to restrict it to approved information and to be careful with prompt design.
Channels
A channel is where users meet the bot: a website chat widget, a team collaboration tool, a messaging app or SMS. The framework aims to let one bot serve several channels. Channels differ in what they can display, such as buttons, cards, images or only plain text, so design the core logic around simple text and treat rich formatting as an enhancement. Each channel also has its own setup, terms and rules, so check them before committing. Messaging by SMS or social apps raises consent and spam questions, covered under messaging bot concerns.
Planning the C# side
Without writing any listing here, a sensible structure is:
- a thin layer that receives activities
- dialogs that hold the conversation logic
- separate services for anything the bot looks up or changes, such as a booking system
- configuration kept outside the code, with secrets stored safely and never committed to public repositories
Following good coding habits matters as much in a bot as anywhere. Keep functions small, name things clearly, and keep the part that decides what to say separate from the part that talks to the outside world, so you can test it without a live connection.
Testing
Bots are easy to under-test because conversation feels informal. Useful practice includes:
- Scripted conversations. Write expected exchanges and check the replies, which is a form of automated testing at the dialog level.
- Local emulation. Frameworks typically offer a local tool for chatting with a bot during development.
- Awkward input. Try empty messages, very long ones, typos, emoji, other languages and abusive text.
- Interruptions. Check what happens if a user says “cancel”, “start again” or “talk to a human” mid-flow.
- Real users. A few people who did not design the bot will find problems quickly.
Limits to be honest about
Bots do not understand people the way a human agent does. They can misread requests, struggle with ambiguity and frustrate users who feel trapped. Reasonable safeguards are a visible way to reach a human, a statement that users are talking to a bot, and no use of the bot for decisions with serious consequences without review. If the bot collects personal data, explain why and how it will be handled, and follow the privacy rules that apply where you operate.
Hosting, scaling and pricing for any managed service vary and change, so read the provider’s current terms before relying on it.
Where to go next
Build the smallest version that handles your top three questions well, put it in front of a few real users, and read the transcripts. Improving a small bot based on real conversations almost always beats adding features in advance.