关于企业微信

This commit is contained in:
2025-12-29 11:48:57 +08:00
parent 42e55f334e
commit dff08f1f84
2 changed files with 284 additions and 0 deletions

View File

@@ -118,6 +118,31 @@ namespace Ramitta.lib
#endregion #endregion
#region #region
public static string? GetExeVersion(string exePath)
{
try
{
if (!File.Exists(exePath))
{
return null; // 文件不存在时返回null
}
var versionInfo = FileVersionInfo.GetVersionInfo(exePath);
string? version = versionInfo.FileVersion;
// 如果FileVersion为空尝试使用ProductVersion
if (string.IsNullOrEmpty(version))
{
version = versionInfo.ProductVersion;
}
return string.IsNullOrEmpty(version) ? null : version;
}
catch
{
return null; // 出现任何异常都返回null
}
}
public static bool IsPathExist(string databasePath) public static bool IsPathExist(string databasePath)
{ {
if (string.IsNullOrWhiteSpace(databasePath)) if (string.IsNullOrWhiteSpace(databasePath))

259
Ramitta/WeComRobot.cs Normal file
View File

@@ -0,0 +1,259 @@
using HelixToolkit.Maths;
using NPOI.HPSF;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace Ramitta
{
public class WeComRobot
{
private readonly string _webhookUrl;
private readonly HttpClient _httpClient;
public WeComRobot(string webhookUrl)
{
_webhookUrl = webhookUrl;
_httpClient = new HttpClient();
}
/// <summary>
/// 发送文本消息
/// </summary>
public async Task<bool> SendTextMessageAsync(string content, string[] mentionedList = null, string[] mentionedMobileList = null)
{
var message = new
{
msgtype = "text",
text = new
{
content = content,
mentioned_list = mentionedList,
mentioned_mobile_list = mentionedMobileList
}
};
return await SendMessageAsync(message);
}
/// <summary>
/// 发送Markdown消息
/// </summary>
public async Task<bool> SendMarkdownMessageAsync(string content)
{
var message = new
{
msgtype = "markdown",
markdown = new
{
content = content
}
};
return await SendMessageAsync(message);
}
/// <summary>
/// 发送图片消息
/// </summary>
public async Task<bool> SendImageMessageAsync(string base64, string md5)
{
var message = new
{
msgtype = "image",
image = new
{
base64 = base64,
md5 = md5
}
};
return await SendMessageAsync(message);
}
/// <summary>
/// 发送图文消息
/// </summary>
public async Task<bool> SendNewsMessageAsync(Article[] articles)
{
var message = new
{
msgtype = "news",
news = new
{
articles = articles
}
};
return await SendMessageAsync(message);
}
/// <summary>
/// 发送文件消息
/// </summary>
public async Task<bool> SendFileMessageAsync(string mediaId)
{
var message = new
{
msgtype = "file",
file = new
{
media_id = mediaId
}
};
return await SendMessageAsync(message);
}
private async Task<bool> SendMessageAsync(object message)
{
try
{
var json = JsonSerializer.Serialize(message);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(_webhookUrl, content);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var result = JsonSerializer.Deserialize<WeComResponse>(responseContent);
return result?.errcode == 0;
}
Console.WriteLine($"发送失败: {responseContent}");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"发送消息异常: {ex.Message}");
return false;
}
}
/// <summary>
/// 上传文件到企业微信并获取media_id (修正版)
/// </summary>
public async Task<string> UploadFileAsync(string filePath,string? fileName=null)
{
try
{
// 1. 从webhook地址中提取key
var uri = new Uri(_webhookUrl);
var key = System.Web.HttpUtility.ParseQueryString(uri.Query)["key"];
string uploadUrl = $"https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={key}&type=file";
// 2. 准备文件和边界
if(fileName==null) fileName = Path.GetFileName(filePath);
var fileBytes = await File.ReadAllBytesAsync(filePath);
string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x"); // 随机边界字符串
string startBoundary = "--" + boundary;
string endBoundary = "--" + boundary + "--";
// 3. 创建并配置HttpWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uploadUrl);
request.Method = "POST";
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Timeout = 30000; // 可根据需要调整超时
// 4. 手动构建并写入请求体(关键步骤)
using (Stream requestStream = await request.GetRequestStreamAsync())
{
using (var writer = new StreamWriter(requestStream, Encoding.UTF8, 1024, true))
{
// 4.1 写入开始边界 (必须有回车换行)
await writer.WriteAsync(startBoundary + "\r\n");
await writer.FlushAsync();
// 4.2 写入文件头信息 (注意格式中的双引号)
string header = $"Content-Disposition: form-data; name=\"media\"; filename=\"{fileName}\"\r\n";
header += "Content-Type: application/octet-stream\r\n";
header += "\r\n"; // 文件头结束后需要一个额外的空行(即两个连续的\r\n
await writer.WriteAsync(header);
await writer.FlushAsync();
// 4.3 直接写入文件字节
await requestStream.WriteAsync(fileBytes, 0, fileBytes.Length);
await writer.WriteAsync("\r\n"); // 文件内容后需要一个回车换行
await writer.FlushAsync();
// 4.4 写入结束边界
await writer.WriteAsync(endBoundary + "\r\n");
await writer.FlushAsync();
}
}
// 5. 获取并解析响应
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string responseContent = await reader.ReadToEndAsync();
Console.WriteLine($"上传响应: {responseContent}");
using (var doc = JsonDocument.Parse(responseContent))
{
if (doc.RootElement.TryGetProperty("media_id", out var mediaIdElement))
{
return mediaIdElement.GetString();
}
else
{
// 解析错误信息
var errcode = doc.RootElement.GetProperty("errcode").GetInt32();
var errmsg = doc.RootElement.GetProperty("errmsg").GetString();
Console.WriteLine($"文件上传失败: errcode={errcode}, errmsg={errmsg}");
return null;
}
}
}
}
catch (WebException ex)
{
// 尝试读取错误响应体
if (ex.Response is HttpWebResponse errorResponse)
{
using (var reader = new StreamReader(errorResponse.GetResponseStream()))
{
string errorContent = await reader.ReadToEndAsync();
Console.WriteLine($"HTTP请求失败 ({errorResponse.StatusCode}): {errorContent}");
}
}
else
{
Console.WriteLine($"网络请求异常: {ex.Message}");
}
return null;
}
catch (Exception ex)
{
Console.WriteLine($"文件上传过程异常: {ex.Message}");
return null;
}
}
}
/// <summary>
/// 图文消息文章
/// </summary>
public class Article
{
public string title { get; set; }
public string description { get; set; }
public string url { get; set; }
public string picurl { get; set; }
}
/// <summary>
/// 企业微信响应
/// </summary>
public class WeComResponse
{
public int errcode { get; set; }
public string errmsg { get; set; }
}
}