如何基于C# Web API实现无Zapier的JIRA Twilio SMS通知
Great job getting the Twilio C# library built—you’re already well on your way! Let’s break down the remaining steps to turn that library into a fully functional SMS notification service tied to Jira webhooks:
1. Build the Web API Endpoint to Handle Jira Webhooks
First, you’ll need to create an ASP.NET Core Web API (or your preferred C# web framework) with a POST endpoint that can:
- Accept Jira’s JSON payloads when events trigger
- Extract critical details from the payload (event type, issue key, assignee, comment text, etc.)
- Call your existing Twilio library to send the formatted SMS
- Validate incoming requests to ensure they’re actually from Jira (critical for security)
Here’s a simplified example of what that controller might look like:
[ApiController] [Route("api/jira-sms")] public class JiraSmsController : ControllerBase { private readonly ITwilioSmsSender _twilioSender; private readonly ILogger<JiraSmsController> _logger; private readonly IConfiguration _config; public JiraSmsController(ITwilioSmsSender twilioSender, ILogger<JiraSmsController> logger, IConfiguration config) { _twilioSender = twilioSender; _logger = logger; _config = config; } [HttpPost] public async Task<IActionResult> ProcessJiraEvent([FromBody] JiraWebhookPayload payload) { try { // Validate Jira's webhook signature to prevent spoofed requests if (!IsValidJiraSignature(Request)) { _logger.LogWarning("Received invalid webhook signature"); return Unauthorized(); } // Extract event type from request headers var eventType = Request.Headers["X-Atlassian-Webhook-Event"].FirstOrDefault(); if (string.IsNullOrEmpty(eventType)) { _logger.LogWarning("No event type found in request headers"); return BadRequest(); } // Get the assignee's phone number (map from Jira user custom fields) var assigneePhone = payload.Issue.Fields.Assignee?.CustomFields .FirstOrDefault(f => f.Id == _config["Jira:PhoneCustomFieldId"])?.Value?.ToString(); if (string.IsNullOrEmpty(assigneePhone)) { _logger.LogInformation("No phone number found for assignee {Assignee}", payload.Issue.Fields.Assignee?.DisplayName); return Ok(); } // Format a concise SMS message based on the event var smsMessage = FormatSmsContent(eventType, payload.Issue); await _twilioSender.SendSmsAsync(assigneePhone, smsMessage); _logger.LogInformation("Successfully sent SMS for event {EventType} to {Phone}", eventType, assigneePhone); return Ok(); } catch (Exception ex) { _logger.LogError(ex, "Failed to process Jira webhook event"); // Return 500 to let Jira know to retry (adjust based on your error handling needs) return StatusCode(500); } } private bool IsValidJiraSignature(HttpRequest request) { // Implement signature validation using the secret you'll set in Jira's webhook config // Reference Atlassian docs for the exact HMAC-SHA256 hashing logic var webhookSecret = _config["Jira:WebhookSecret"]; // ... add actual validation logic here ... return true; // Replace with real validation } private string FormatSmsContent(string eventType, JiraIssue issue) { return eventType switch { "jira:issue_created" => $"New Jira Issue: {issue.Key} - {issue.Fields.Summary}", "jira:issue_updated" => $"Jira Issue Updated: {issue.Key} (Status: {issue.Fields.Status.Name})", "comment_created" => $"New Comment on {issue.Key}: {issue.Fields.Comments.Last().Body.Substring(0, 100)}...", _ => $"Jira Event: {eventType} for {issue.Key}" }; } } // Add model classes to deserialize Jira's payload (use tools like Json2CSharp to generate these) public class JiraWebhookPayload { public JiraIssue Issue { get; set; } } public class JiraIssue { public string Key { get; set; } public JiraIssueFields Fields { get; set; } } public class JiraIssueFields { public string Summary { get; set; } public JiraUser Assignee { get; set; } public JiraStatus Status { get; set; } public List<JiraComment> Comments { get; set; } }
2. Securely Configure Sensitive Data
Never hardcode Twilio credentials (Account SID, Auth Token, phone number) or Jira webhook secrets in your code. Instead:
- Use
appsettings.jsonwith environment-specific overrides - Store secrets in environment variables (ideal for production)
- For cloud deployments, use secure secret managers like Azure Key Vault or AWS Secrets Manager
3. Deploy the API to a Publicly Accessible Server
Jira needs to reach your webhook endpoint, so deploy it to a server with a public URL:
- Options include Azure App Service, AWS Elastic Beanstalk, a self-hosted server with a public IP, or ngrok for testing
- Ensure the server uses HTTPS (Jira requires webhook URLs to be secure)
4. Test the Endpoint Before Connecting to Jira
Validate your API works before linking to Jira:
- Use Postman or curl to send a sample Jira webhook payload (grab examples from Atlassian’s docs)
- Verify the API parses the payload, calls Twilio, and sends an SMS successfully
- Test error scenarios (invalid payload, missing phone number, Twilio outage) to ensure logging and error handling works as expected
5. Configure Jira Webhook
Once your API is live and tested:
- Log into your Jira instance
- Go to Settings > System > Webhooks
- Click Create webhook
- Fill in the details:
- Name: Descriptive name (e.g., "Jira SMS Notifications")
- URL: Your API’s public endpoint URL (e.g.,
https://your-api-domain.com/api/jira-sms) - Events: Select events matching Jira’s email notifications (Issue Created, Issue Updated, Comment Added, etc.)
- Secret: Set a strong secret key (use this in your API’s signature validation)
- Ensure HTTP method is POST and Content type is JSON
- Save the webhook
6. Add Logging & Monitoring
To keep your service reliable:
- Implement structured logging (Serilog, NLog, or Microsoft’s built-in logging) to track requests, SMS statuses, and errors
- Set up monitoring (Azure Monitor, Prometheus) to alert you if the service goes down or SMS send rates drop
- Add a fallback mechanism (e.g., queue failed SMS attempts for later retries)
7. Handle Edge Cases
Don’t overlook these details:
- User Phone Numbers: Ensure Jira users have their phone numbers stored in a custom user field (map this field ID in your API)
- SMS Length Limits: Twilio limits standard SMS to 160 characters—truncate messages or handle multi-part SMS if needed
- Idempotency: Jira may retry webhooks on failure—add logic to skip duplicates (use Jira’s
X-Atlassian-Webhook-Identifierheader or event IDs)
内容的提问来源于stack exchange,提问作者user1796762

