using System;
using System.IO;
namespace Apewer.Web
{
/// Response 模型。
public abstract class ApiModel
{
#region
private int _expires = 0;
internal ApiRequest _request;
internal ApiResponse _response;
internal ApiOptions _options;
internal ApiProvider _provider;
static int SafeExpires(int seconds)
{
var s = seconds;
if (s < 0) s = 0;
if (s > 2592000) s = 2592000;
return s;
}
#endregion
#region 内部属性和方法。
/// 处理当前模型的 API 请求。
protected ApiRequest Request { get => _request; }
/// 处理当前模型的 API 响应。
protected ApiResponse Response { get => Response; }
/// 处理当前模型的 API 选项。
protected ApiOptions Options { get => _options; }
/// 处理当前模型的服务程序实例。
protected ApiProvider Provider { get => _provider; }
/// 在 Response 头中添加用于设置文件名的属性。
protected void SetAttachment()
{
if (Provider == null) return;
var name = Attachment;
if (string.IsNullOrEmpty(name)) return;
var encoded = TextUtility.EncodeUrl(name);
Provider.SetHeader("Content-Disposition", $"attachment; filename={encoded}");
}
/// 以指定参数输出。
protected void Output(byte[] bytes)
{
if (Provider == null) return;
try
{
SetAttachment();
Provider.SetCache(Expires);
Provider.SetContentType(ContentType);
var length = bytes == null ? 0 : bytes.Length;
Provider.SetContentLength(length);
if (length > 0) Provider.ResponseBody().Write(bytes);
}
catch { }
}
/// 以指定参数输出。
protected void Output(Stream stream, bool dispose)
{
if (Provider == null) return;
try
{
SetAttachment();
Provider.SetCache(Expires);
Provider.SetContentType(ContentType);
Provider.SetContentLength(stream.Length - stream.Position);
Provider.ResponseBody().Write(stream);
}
catch { }
if (dispose) RuntimeUtility.Dispose(stream);
}
#endregion
/// 内容类型。
public virtual string ContentType { get; set; }
/// 响应缓存的过期时间,以秒为单位。
public virtual int Expires { get => _expires; set => _expires = SafeExpires(value); }
/// 设置文件名,告知客户端此附件处理此响应。
public virtual string Attachment { get; set; }
/// 执行输出。
/// 此方法由 API 调用器发起调用,用户程序不应主动调用。
///
public abstract void Output();
/// 创建对象实例,并设置默认属性。
public ApiModel()
{
ContentType = "application/octet-stream";
Expires = 0;
Attachment = null;
}
}
/// 输出二进制的 Response 模型。
public class ApiBytesModel : ApiModel
{
/// 向 Body 写入的字节数组。
public byte[] Bytes { get; set; }
/// 输出字节数组。
public override void Output() => Output(Bytes);
}
/// 输出二进制的 Response 模型。
public class ApiStreamModel : ApiModel, IDisposable
{
/// 将要读取的流,用于向 Body 写入。
public Stream Stream { get; set; }
/// 执行输出后释放流。
/// 默认值:TRUE。
public bool AutoDispose { get; set; }
/// 输出流。
public override void Output() => Output(Stream, AutoDispose);
/// 当指定 AutoDispose 属性时释放流。
public void Dispose()
{
if (AutoDispose) RuntimeUtility.Dispose(Stream);
}
/// 创建对象实例,并设置默认属性。
public ApiStreamModel() => AutoDispose = true;
}
/// 输出二进制的 Response 模型。
public class ApiFileModel : ApiModel
{
/// 将要读取的文件所在路径,用于向 Body 写入。
public string Path { get; set; }
/// 输出指定路径的文件。
public override void Output()
{
try
{
if (!File.Exists(Path)) return;
var info = new FileInfo(Path);
if (string.IsNullOrEmpty(Attachment)) Attachment = info.Name;
var stream = new FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.Read);
Output(stream, true);
}
catch { }
}
}
/// 输出文本的 Response 模型。
public class ApiTextModel : ApiModel
{
/// 自定义文本。
public string Text { get; set; }
/// 输出文本。
public override void Output() => Output(TextUtility.Bytes(Text));
/// 创建对象实例,并设置默认属性。
public ApiTextModel() => ContentType = "text/plain; charset=utf-8";
}
/// 输出文本的 Response 模型。
public class ApiJsonModel : ApiModel
{
/// Json 对象。
public Json Json { get; set; }
/// 缩进排版。
/// 默认值:TRUE
public bool Indented { get; set; }
/// 转为属性名为驼峰形式。
/// 默认值:FALSE
public bool Camel { get; set; }
/// 输出文本。
public override void Output()
{
var json = (Json != null && Json.Available) ? Json : Json.NewObject();
if (Camel) Json.Camel(json);
Output(TextUtility.Bytes(json.ToString(Indented)));
}
/// 创建对象实例,并设置默认属性。
public ApiJsonModel()
{
ContentType = "text/plain; charset=utf-8";
Indented = true;
}
}
/// 输出重定向的 Response 模型。
public class ApiRedirectModel : ApiModel
{
/// 将要重定向的位置。
public string Location { get; set; }
/// 执行重定向。
public override void Output()
{
var location = Location;
if (string.IsNullOrEmpty(location)) return;
if (Provider == null) return;
Provider.SetRedirect(Location);
}
}
/// 输出带有指定 Status 的 Response 模型。
public class ApiStatusModel : ApiModel
{
/// 状态。
/// 默认值:200。
public int Status { get; set; } = 200;
/// 向 Body 写入的字节数组。
public byte[] Bytes { get; set; }
/// 执行重定向。
public override void Output()
{
var status = Status > 0 ? Status : 200;
Provider.SetStatus(status.ToString());
Output(Bytes);
}
///
public ApiStatusModel() { }
///
public ApiStatusModel(int status)
{
Status = status;
}
}
}