Cloud over IFileSystemInfo Extension (Cofe3) - Part I





0/5 (0投票)
使用类似 FSI 接口设计 RESTful 家庭云服务的框架库。
本文档介绍了 Cofe3 (Cloud Over IFileSystemInfo Extension 3),这是一个使用类似 FSI 接口设计 RESTful 家庭云服务的框架库。
引言
Cofe3 是一组库,使开发人员能够为其特定类型的条目(例如,**IFileSystemInfo/CofeIO 只是一个实现**)构建家庭云服务,让用户可以在自己的计算机上托管它们,并通过网络浏览器或应用程序将其用于服务其自己的瘦客户端计算机,如智能手机和平板电脑。该库根据 **LGPL** 许可发布。
Cofe3 是一个开发者友好的实现,核心库类似于 `System.IO.FileSystemInfo`,不同之处在于条目现在是一个名为 `Cofe.Core.ICofeSystemInfo` (entries) 的接口。开发人员可以选择开发自己的条目(派生自 `ICofeSystemInfo`),或者他们可以向现有条目添加新的属性或操作(例如,为 JPG `IFileInfo` 添加 `ExifProperties`),这两种方式都将使它们能够存储在数据库中,可搜索并在网络上访问,就像 Cofe.IO 库中的 `IFileSystemInfo` 一样。但请记住,在幕后,Cofe3 的实现与 `System.IO` 有很大不同,不应认为自定义实现与继承一个类一样轻松。
CofeWs3 使用 ASP.NET MVC3 托管服务器,提供身份验证支持,访问 API 至少需要一个用户(`[Authorize]` 标签),并且 Cofe 端有卷权限和用户角色检查。配置将作为 MVC 网页开发,但访问 CofeSystem 则不会。CofeWs3 和用户瘦客户端之间的通信是基于 REST 的 API,主要通过 JSON,事件使用 Atom10,而不是 ViewBag。这允许开发第三方应用程序。
CofeDb3 基于 Entity Framework Code First,这允许第三方插入其条目表以用于 CofeSystemInfos;开发人员也可以选择将属性保存在 PropertyPairs 表中(例如,用于 `int` 值的 `PropertyPair_Int32`)。无论我们缓存数据的方式如何,两种方式都允许用户使用 `FilterString` 搜索其整个集合,这类似于在搜索引擎中搜索字符串。
背景
本项目经历了多次迭代。
Cofe1 的作用是将档案文件(由 Cake 和 SevenZipSharp 支持)整合到文件系统(参见 DirectoryInfoEx)中,从而允许像 DirectoryInfo 那样浏览档案文件;它是我的 zip 软件程序的主要部分之一。在完成 FileExplorer2 之后,我开始开发 Cofe2,这实际上是我的毕业设计项目。Cofe2 的早期版本非常原始,它使用硬编码的 SQL 与数据库通信,以及我自己的 JSON 到 XML(反之亦然)转换器。Cofe2 的最终版本使用 Entity Framework 模型优先,仅支持文件,并且只支持基于文本的安全功能。
放弃 Cofe2 转而开发 Cofe3 的主要原因是利用最新的框架来完成我无法实现的任务,即 MVC3 中的安全性和使用 EF Code First 实现非硬编码条目,以支持将操作/任务作为属性,从而允许在 WebAPI 中调用,使用 GET(例如,`CofeDirectoryProperties.List`)或 DELETE(例如,`CofeProperties.DeleteAsync`)操作,并通过 Code First 支持非文件条目。
我想强调的是,自 Cofe2 早期阶段以来,该项目已在 CodePlex 上根据 LGPL 许可发布。家庭云存储确实会访问用户最敏感的数据,因此我的最初想法是它必须提供信任,让用户了解他们正在运行什么,并且不应该被用来不公平地利用用户。
我已尽力使网络服务尽可能安全,但由于我并非此方面的专家,可能存在一些不安全的代码,如果您发现任何问题,请向我报告。
未完成事项
即使经过长时间开发,仍有一些重要但未完成的事项,以下是列表:
将 Web.Services 中的数据库更新代码分离到 Windows 服务中 - 重要
目前,Cofe.Web.Services 启动时会创建三个线程,两个 ActiveUpdater 用于更新数据库中的过期条目和列表,一个以上事件源用于监听 `System.IO.FileSystemEvents` 并触发 `Cofe.Core.CofeSystemEvent`。问题是,当 ASP.NET 因各种原因刷新 AppDomain 时,它会销毁我的线程。为了解决这个问题,我需要将数据库更新代码分离并使其成为 Windows 服务或控制台应用程序,或者使用 WebAPI Self-Host。
修复 WinRT 实现
Cofe 的早期版本在 Cofe.Core 和 Cofe.IO 中支持 WinRT(没有 EntityFramework.RT,因此也没有 Cofe.Data.RT),但在开发 WebServices 后我停止了更新。目前该版本无法编译。希望我能让这两个库再次工作,并添加 Cofe.Media.RT 库。
改进 HTML5 客户端/添加 WPF 客户端
目前,当咖啡系统发生变化时,HTML5 客户端不会自动更新。它可以从提要接收咖啡系统变化事件,但它不会更新网页 UI。
数据库更新和条目操作的脚本支持
Cofe 确实提供了 `IScriptService` 来解析和运行脚本,但它唯一的作用是在 CofeWs 中创建事件提要。我正在考虑将其扩展以支持 CofeSystem。
目录
本文分为两部分,第一部分将快速浏览 Cofe3 提供的功能以及如何使用它。第二部分将尝试简要解释其内部工作原理。
第一部分
- 库
- Cofe3 - Cofe.Core, Cofe.IO, 和 Cofe.Media
- CofeDb3 - Cofe.Data
- CofeWs3 - Cofe.Web 和 Cofe.Web.Services
- Cofe 作为通用库
- Cofe 作为网络服务
库
- Cofe.Core - 主库,提供 CofeSystem 正常工作所需的所有服务,它还包括所有条目(`ICofeSystemInfo`)的根接口,以及其他几个接口(`ICofeItemInfo`,`ICofeDirectoryInfo`)。
- Cofe.IO - `System.IO` 的 Cofe 实现,增加了对 `IFileSystemInfo` 的支持。
- Cofe.Media - Cofe 的媒体实现,目前只解析 JPG 图像中的 EXIF 标签,为任何名称以 *jpg* 结尾并支持 `CofeStreamProperties.OpenStreamAsync` 的条目提供 `IMediaInfo` 和 `IImageInfo` 接口。
- Cofe.Data - 将条目及其属性缓存到数据库中,将搜索字符串 (`EntryFiltersString`) 转换为 SQL 语句进行查询。
- Cofe.Web - 提供 Web 服务实现,包括事件更新和条目格式化。
- Cofe.Web.Services - ASP.NET 应用程序,包含提供 Web API 的 APIController 和访问 API 的 JavaScript。
Cofe 作为通用库
LinqPad
在 * \doc\LinqPad\Tutorial* 中有许多 LINQ 文件用于演示,我主要用于调试和测试。
数据库相关的 LINQ 文件抱怨迁移问题,这是由于 Cofe.Media 未链接到这些 LINQ 文件造成的,再次运行 LINQ 即可解决问题。
配置
在使用 Cofe3 之前,您必须配置两件事,一是确定要使用哪个库,然后注册卷。
注册库
要注册库,我们可以使用 ModuleBootStrapper。该库在其命名空间中包含一个 `RegisterModule` 类;例如,`Cofe.IO` 中的 `Cofe.IO.RegisterModule`,您必须在 `MofuleBootStrapper` 的构造函数中包含所有 `RegisterModule`,例如(`registerModule` 的顺序无关紧要)
new ModuleBootStrapper(true,
new Cofe.Core.RegisterModule(),
new Cofe.IO.RegisterModule()
).Run();
上述示例仅包含 Cofe 和 IO,这是 Cofe3 工作所需的最低限度;您可以注册 IO 提供的卷,但这种情况下将没有数据库支持,搜索将通过迭代子目录完成。
new ModuleBootStrapper(true,
new Cofe.Core.RegisterModule(),
new Cofe.Data.RegisterModule(true, CacheUpdateOptions.Manual),
new Cofe.IO.RegisterModule(),
new Cofe.Media.RegisterModule()
).Run();
上述示例添加了 Data 和 Media,您现在可以使用 `.As()` 方法将文件“转换为”`IImageInfo`,并且现在包含了数据库支持。请注意,`CacheUpdateOptions` 设置为 `Manual`。
CacheUpdateOptions
- 手动 (测试) - 用户必须手动调用 `DatabaseProperties.WriteRepositoryAsync` 以更新数据库。
- 被动 (桌面) - 用户解析或列出条目时自动更新。
- 主动 (WebServices) - 创建后台线程来查找过期条目或列表并在后台更新。
注册卷
卷由已注册的 `IVolumeFactory` 提供。目前唯一可用的卷是 `Cofe.IO` 提供的 `CofeIO`。
要注册 CofeIO 卷,您必须指定 `VolumePath` 参数,它是 `CofeIO` 要使用的根目录(您可以同时映射多个卷)
await VolumeFE.MapAsync("CofeIO", "cofe", Tuple.Create("VolumePath", "c:\\cofe"));
这将赋予所有用户 CRUD 目录的权限;对于 Web 用户,您应该指定权限,例如
VolumeFE.Unmap("cofe");
await VolumeFE.MapAsync(PermissionType.None, "CofeIO", "cofe", Tuple.Create("VolumePath", "c:\\cofe"));
VolumeFE.GrantPermission(new string[] { "Admin" }, "cofe", PermissionType.All);
`VolumeFE.Factories` 显示已注册工厂列表,而 `VolumeFE.Volumes` 返回已注册卷列表。
每次应用程序启动时设置卷和权限可能会很麻烦,因此您可以在更新卷和权限时使用 `CofeSettings` 类,它也会更新 `CofeServices.CofeSettings.Permissions/Volumes`,并且这些设置可以保存到外部文件(默认外部存储)。然后您可以在应用程序重新启动时恢复它们。
await CofeServices.SaveAsync();
await CofeServices.RestoreAsync(); //Do not call CofeServices.CofeSettings.Save/RestoreAsync() directly.

助手类
不同的类中有很多有用的方法,可能很难记住。Cofe3 提供了一些静态助手类,它们调用那些经常使用的方法。这些助手类都以 FE 结尾。
- Cofe.Core.CofeServices - CofeServices 是访问 Cofe 中所有服务的中心。所有服务都实现了 `ICofeServices`,因此开发人员可以调用 `CofeServices.ServicesLocater.FindServices<>()` 来查找所需的服务接口。其中一些服务包括 ServicesLocater、EntryConstructor、PropertyDictionary、PathParser 和 EntrySerializer。
- Cofe.Core.PathFE - 一些路径相关的实用工具。Cofe 路径包含 {} 字母,使其与 `System.IO.Path` 不兼容(等同于 `System.IO.Path`)。
- Cofe.Core.EntryFE - 条目(`ICofeSystemInfo`)相关辅助函数,包括路径解析(TryParsePath/Exists)、传输(Move/Copy/Rename/LinkAsync)和搜索(SearchAsync)
- Cofe.Core.VolumeFE - 列出和注册卷,为角色分配权限(相当于 `System.IO.Drive`)。
- Cofe.Core.UserFE - 将角色分配给用户。
- Cofe.Core.EntryListFE - EntryList 相关辅助函数,包括路径解析和 EntryList 构建。
- Cofe.Core.LinkFE - 获取或设置条目链接。
- Cofe.IO.FileFE - 文件(`IFileInfo`)相关辅助函数(相当于 `System.IO.File`)。
- Cofe.IO.DirectoryFE - 目录(`IDirectoryInfo`)相关辅助函数(相当于 `System.Directory`)。
条目
尽管 Cofe 系统中最小的数据片段是属性对,但条目是 Cofe 系统中的业务实体。根据您正在开发的内容,它可能表示一个 IO 项目(文件/目录)、一个人的联系方式,甚至是一个 Word 文档的某个部分。
一旦您在上一节中注册了一个卷,它就在 Cofe 系统中,您可以使用路径解析它
IDirectoryInfo rootDirectory = rootEntry.As<IDirectoryInfo>();
rootDirectory = await EntryFE.TryParsePathAsync<IDirectoryInfo>("{cofe}"); //Or specify the type directory
rootDirectory = DirectoryFE.FromDirectoryPathAsync("{cofe}"); //Or using DirectoryFE helper class.
IFileInfo file1 = await FileFE.FromFilePathAsync("{cofe}\\testParse1.txt");
Console.WriteLine(file1.Length);
如果一个条目是从 `EntryFE.TryParsePathAsync()` 解析的,它返回 `ICofeSystemInfo`,`rootEntry` 不一定已经实现了 `IDirectoryInfo` 类,所以您必须调用 cast `As
`Cofe.IO.IDirectoryInfo` 继承自 `ICofeDirectoryInfo`/`IFileSystemInfo`,然后是 `ICofeSystemInfo`,而 `Cofe.IO.IFileInfo` 继承自 `ICofeItemInfo`/`IFileSystemInfo`,然后是 `ICofeSystemInfo`,`System.IO` 有 `FileInfo` 和 `DirectoryInfo` 的实现。因此,为了允许访问档案文件的 `IDirectoryInfo` 和 `IFileInfo` 属性,我们必须使用 `As
所有接口都实现了 `ICofeSystemInfo`。`ICofeSystemInfo` 具有一些重要的属性:`Properties` 和 `EntryTypeInfo`。
`Properties` 属性是一个 `IPropertyHost`,负责访问条目的所有其他属性(例如,长度、md5)和操作(例如,`DeleteAsync`、`List`)。当您调用 `DeleteAsync` 时,实际上是从一组 PropertyProviders 获取 `Func
`EntryTypeInfo` 是 `IPropertyHost` 提供的一个属性,它提供条目的类型信息。在以前,`FileSystemInfo` 中没有文件类型信息,而且由于涉及 WinAPI,解析每个条目的类型信息非常消耗资源,因此描述和图标等类型信息存储在外部字典中。基于外部内存的缓存适用于桌面应用程序但不适用于 Web 服务,我决定包含 `IEntryTypeInfo` 的实现,它可以在数据库中缓存。
上图中的二进制数字 (`byte[]`) 用于 EntityFramework 缓存图标,其 `IEntryTypeInfo.LargeIcon` 返回一个 `BitmapContainer` 对象,其中包含 `BitmapSource`,允许您在 WPF 应用程序中使用。
目录
`ICofeDirectoryInfo` 支持子条目的列表和创建。对于列表,`ICofeDirectoryInfoExtension` 提供了一系列 `EnumerateCofeSystemInfos()` 和 `GetCofeSystemInfosAsync()` 方法,这些方法将 `FilterCollections` 作为参数。
`FilterCollection` 用于指定要返回的内容。虽然我们可以使用 `FilterCollection.FromParseName()`、`FromName()` 等来生成一个简单的查询,但您可以在 `FilterCollection` 中使用多个条目和选项过滤器。要创建这些过滤器,我们可以使用 `FilterCollections.FromFilterString()` 方法,它将过滤器字符串转换为 `Entry`/`OptionFilter` 对象,例如
var filterStrList = rootDir.EnumerateCofeSystemInfos(
FilterCollections.FromFilterString("filetype:txt size:>0").AndProperty(
CofeItemProperties.Length, "<100")).Select(e => e.ParseName);
对于 `IDirectoryInfo`,我们可以使用 `EnumerateFileSystemInfos()` 和 `GetFileSystemInfosAsync()` 方法,这些方法与 `DirectoryInfo.EnumerateFileSystemInfos()` 一样,接受文件名模式和 SearchOptions。
搜索
在上一节中,我们使用 `EntryFE.TryParsePathAsync()` 返回一个条目,使用 `Get`/`EnumerateCofe`/`FileSystemInfos` 列出子内容,并使用了数据库。我们可以跳过分层查找并轻松搜索条目。同样,`FilterCollections` 对于搜索很重要,所有 `EntryFilter` 和 `OptionFilter` 都转换为一个 `EntryFilterExpression`,它是一个 `Expression
搜索通过使用 `EntryFE.SearchAsync()` 和 `FilterString` 完成
IAutoEntryList el = await EntryFE.SearchAsync("name:testParse* filetype:txt size:<100 root:{cofe}");
foreach (ICofeSystemInfo e in await entryList.GetCofeSystemInfosAsync())
String.Format("{0} ({1})", e.ParseName, e.GetType().Name).Dump();
组织条目
上面描述的信息主要处理原始层次结构的条目。用户可能希望有另一种方式来分类项目。目前 Cofe3 确实提供了多种方式来组织 CofeSystem 中的条目:标签、链接和自定义条目列表。
标签 (需要数据库)
标签是适用于任何数据库条目的哈希标签,用户可以使用它来对条目进行分类。它需要数据库,因为其实现是一个从项目链接到标签的一对多表。
一旦条目进入数据库,您就可以调用条目的 `.AddTags()`、`RemoveTags()` 和 `GetTags()` 扩展方法(在 CofeDB3 中)来添加、删除和访问标签信息。标签参数以逗号分隔,因此您可以一次添加/删除多个标签。
搜索通过使用 `tags` 属性完成,请注意目前不支持逗号。
链接
`IEntryLink` 允许任何条目链接到另一个条目,通过调用 `LinkFE.AddLinks(entry, entryToAddLink)` 辅助方法。它告诉 Cofe3 创建一个新的 `IEntryLink` 条目,该条目从第一个条目链接到第二个条目。下面是调用命令后数据库的外观。
`LinkFE.EnumerateLinks()` 方法返回特定条目的条目链接列表。它们都是 `IEntryLink`,因此要获取实际条目,您必须访问其 `IEntryLink.Entry` 属性,或者您可以调用 `IEntryLink.As
要删除链接,请调用链接的 `DeleteLink()` 方法。如果您调用 `DeleteAsync()` 方法,它将删除您的实际条目。
CustomEntryList
组织条目的另一种方式是 `CustomEntryList`;像 `IAutoEntryList` 一样,它包含许多条目,但 `CustomEntryList` 不是由搜索字符串构建的。用户通过链接它们来自己构建列表。
`CustomEntryList` 与 Cofe 中其他目录的区别在于,它是一个数据库或内存中的虚拟项,最重要的是,它的 `ListCore` 方法返回上一节中描述的添加链接,而其他目录返回它们的子项而不是它们的链接。因为这些链接可以使用 `.As
以下示例演示如何将自定义条目列表创建为卷,以及如何添加项目和子 `CustomEntryList` 并更改特定项目的位置
ICustomEntryList cel = EntryListFE.NewEntryList("cel");
cel = await cel.MakeParsbleAsync();
await cel.AddLinksAsync(file2add);
IEntryLink subdirLink = cel.CreateLinkFolder("sub");
ICustomEntryList subCel = subdirLink.As<ICustomEntryList>();
subdirLink.Position = 1; //Change position for an entry.
await subCel.AddLinksAsync(file2add);
它在数据库中看起来会像这样(请注意,这些 ID 字段应该是 GUID 格式)
`EntryListFE.FromPathAsync()` 调用 `EntryFE.TryParsePath()` 并带有一个查找参数,可以解析作为卷的自定义条目列表
Cofe 作为 Web 服务
管理
目前可以管理两件事:用户角色和卷信息。编辑它们需要管理员权限,您必须创建一个用户,然后在 `ImmediateWindow` 中运行 `Cofe.Web.SecurityConfig.RegisterAsAdmin("您的用户名");`。
用户角色
因为该软件是为家庭使用而设计的,我创建了几个角色 - Admin / Me / FamilyMember / Friend / Other。
服务器地址是 *{server}/admin/permission*,您可以更改除管理员之外的任何注册用户的角色。
卷
`Volume` 是上一节中的 `VolumeInfo`,它定义了根目录。该页面只是 `VolumeFE.MapAsync()` 方法的在线版本,支持权限。请注意,您可以为不同的角色设置不同的权限。
RESTful API
除了用于桌面的 `IFileSystemInfo` 接口之外,Cofe3 还可以通过 RESTful API 进行访问,这些 API **不**基于 SOAP,它们使用 HTTP 的 GET/PUT/POST/DELETE 操作来检索和操作 Cofe 系统。以下是已实现的 API 的简要列表
- /api/entry - 使用 GUID 访问条目的属性、资源和操作。
- /api/entryList - 构建一组条目(未完成)。
- /api/parse - 使用解析路径,重定向到相应的 */api/entry* 路径。
- /api/search - 使用过滤器字符串进行搜索。
- /api/events - 使用 ATOM RSS 提要返回 Cofe 系统更改。
条目 API 控制器 - /api/entry/
条目 API 控制器是访问 Cofe3 中特定条目、其元数据(属性)、资源和操作的主要方式;这些类别类型在下表中描述
人们可能想知道 Cofe3 如何区分不同类别的属性。实际上,它们是在属性中精确定义的,例如,`CofeProperties.RefreshAsync` 将其别名设置为 refresh,它是一个操作和 Web 操作。换句话说,它们的编码方式是您可以随时更改在哪个类别中显示什么以及任何别名。
以下是 */entry/{guid}* 的示例输出,您可以看到信息以 JSON 格式显示。元数据被序列化为 JSON 属性,而资源和操作则序列化在 links 数组中。Links 节点允许 JSON 用户发现可用服务。
我们应该使用 `rel` 属性来查找适当的操作链接。链接中的 `rel` 属性表示其与当前条目的关系,除了 self,它表示访问条目本身的 URL;其他链接是资源和操作,`rel` 实际上是其别名。`mediaType` 属性表示要返回的 MIME 类型。目前没有指示区分资源和操作(前者需要 GET,后者需要 POST 操作),或者支持哪些参数。
条目及其资源支持 HTTP 级别缓存,条目基于 `LastModified`/`IfModifiedSince` HTTP 头部(从 `CacheProperties.LastCachedTimeUtc` 或 `LastListTimeUtc` 加载),而资源取决于属性的 `WebResourceAttribute.CacheMethod` (`None`/`LastModified`/`MaxAge`)。
删除 - DELETE /api/entry/{guid}
这在条目的 JSON 中没有宣传,但您可以使用 DELETE 操作删除一个条目。
创建 - PUT /api/entry
创建条目通过使用带有查询字符串或 JSON 数据的 PUT 操作完成,新创建的条目将被返回。对于文件,用户需要通过 POST 请求其流地址(*/api/entry/{guid}/stream*)并附带流内容。
基于表单的上传 - POST /api/entry/{guid}/upload
有些人可能希望使用表单的文件输入来上传文件,这可以通过 POST */api/entry/{guid-of-root}/upload* 或 */api/parse?path={cofe}&rel=upload* 来实现。
列表 - GET /api/entry/{guid}/List
列表资源返回其子内容,它们也是 JSON 格式,所有条目都在 *entries* 数组中。为了减少带宽,并非所有元数据/资源/操作都显示在此条目中,您必须调用其自身链接才能获取所有这些信息。
EntryType - GET /api/entry/{guid}/typeInfo
所有具有类型信息的条目都将暴露其 TypeInfo 链接。TypeInfo 是可以与许多条目共享的属性,例如下面显示的 MIME 和文件类型,但最重要的是其图标资源。您可以使用适当的链接以各种大小访问其图标,因为同一类型文件的图标 URL 相同,这允许重复使用缓存的图标(在浏览器上)。
更新标签 - POST /api/entry/{guid}/addtag
这与本文前面部分中的命令相同,`AddTag()` 方法调用 `UserFeedbackProperties.AddTag`,带有一个 `TagNames` 标签。在 Web 服务中,您可以直接调用 `AddTag` 属性,并且 `TagNames` 参数嵌入在查询字符串中。由于它更新 Cofe 系统,`UserFeedbackProperties.AddTag` 是一个 WebAction,需要 POST,并且返回更新后的条目。RemoveTag 命令类似。
您还可以使用 - POST /entry/{guid} 仅包含标签值来替换 `Tags` 属性,CofeWS 将尝试更新您上传中的所有属性,除了 ID 和解析名称。
EntryList API控制器 - /api/entryList
执行操作 - POST /entryList/{action}
大多数时候我们必须处理多个条目而不是一个。与其为每个条目运行一个请求,我们可以将它们分组在一个只包含 ID 的 JSON 条目列表中(其他属性被丢弃),然后进行 POST。上面的屏幕截图实际上使用的是 */entryList* 而不是 */entry*。
获取属性 - GET /entryList
类似地,如果您想获取多个条目的属性,您可以创建一个包含 ID 的 JSON 条目列表,Web 服务将返回完整的条目。
更新属性 - POST /entryList
更新属性是通过 POST 包含要更改的 ID 和属性的 JSON 条目列表来完成的。
解析 API 控制器 - /api/parse
使用 EntryApiController 可以处理条目的大部分工作,但要访问任何条目,我们必须拥有其 GUID。`ParseApiController` 接受一个 ParseName 并重定向到 EntryApiController 中相应的位置。为了降低复杂性,参数附加在查询字符串中
- path - 条目路径(例如,*path={cofe}\testParse1.txt*)
- rel - 如果要调用特定资源或操作,可以指定该条目的 rel(关系),rel 列表可在条目的链接中找到。
请注意,目前只有 GET 完全支持并重定向到 EntryAPIController 中相应的 URL。虽然 POST 可能有效,但它直接在 `ParseAPIController` 中调用资源或操作。
搜索 API 控制器 - /api/search
条目的所有元数据都存储在数据库中并可搜索,最简单的搜索方式是使用搜索字符串。搜索 `APIController` 接受 `filterStr` 参数并返回符合条件的条目列表。
除了少数情况外,大多数属性都通过 `PropertyEntryFilter` 支持,对于这些属性,您必须使用其别名(没有别名的属性,如下面显示的文件属性,不起作用)。
您可以使用分页 (page) 过滤器来控制显示数量,`SortResult` (sort) 来控制列表的排序方式,以及 `searchOption` (subdir) 过滤器来控制是否搜索子目录。
事件 API 控制器 - GET /api/events
当 Cofe 系统发生变化时,它会生成事件,然后这些事件被传输到 EventHub,再传输到 Cofe3.Web 中的 feed 写入器。feed 写入代码取自《REST in practice》一书,但我对代码进行了修改,以适应 Cofe3 中现有类。
Web 服务有一个线程会定期更新 feed,当 feed 满了,就会创建一个新的。当您调用 */api/events* 时,您会被重定向到内存中最新的 feed,或者您可以带上查询字符串 page={page#} 调用,以指定要显示的事件页。
探索
浏览页面的网页界面(/explore)相当基础,我不是网页设计师,所以这是我在有限的时间内能创建的。
它分为几个部分
- 目录树 - 显示子目录,当目录更改时自动更新。
- 条目列表 - 显示目录或搜索中的所有条目,每次显示 20 项,当用户滚动到底部时激活分页刷新。使用拖放上传文件。
- 搜索 - 允许用户输入过滤字符串,Web 界面调用 `SearchAPIController`,并返回结果。
- 元数据 - 当选择一项时,显示条目中找到的所有元数据,否则显示“x 项已选择”。
如果所选项目是带有 GeoTag EXIF 数据的照片,则会显示一张 Google 地图,并标记位置。虽然元数据是从 JSON 生成的,但操作是硬编码的。
底层组件使用 SpineJS、CoffeeScript 和 jQueryUI 编写,它们只与上述章节中描述的 WebAPI 服务器通信。
结论
这可能是有史以来最愚蠢的项目之一,在一个在线公司为每个人提供 API 以存储和处理所有类型数据,拥有比您本地硬盘更大的空间,更快,免费的世界里,创建一个基于网络的 Web 服务来服务所有个人数据。但我认为,无论一家公司多么不邪恶,归根结底,如何使用您的个人数据,是否继续提供对某些服务或 API 的访问,在请求删除后他们会保留数据多久,以及最重要的是,他们多久更改一次许可协议,都是一项业务决策,并非总是合乎道德的。
许多因素促使我将开发从 Cofe1(一个纯桌面组件)转向 Cofe3(一个作为 Web 服务的桌面)。其中,关于 RESTful Web 服务的有趣书籍,WCF、MVCWebApi 和 EntityFramework 等新技术的可用性,毕业设计项目以及在线环境氛围的变化是主要原因。
在我开发 Cofe1 和 DirectoryInfoEx 时,我从未想过 Cofe 会成为一个 Web 服务。这花费了很长时间,在整个过程中学到了很多新技术,我享受了这一切。我希望开发能够继续,那些需要此类服务的人能够受益。
尽管我的项目功能不如丰富,性能不如好,甚至不如在线选项稳定,甚至可能不如安全,但希望阅读本文后,我能说服您,您自己的家庭 Web 服务可以做的远不止某种文件服务服务器。
参考文献
- REST in Practice - O'Reilly Media 2010 (Jim Webber, Savas Parastatidis, Ian Robinson)
- 重构 .NET - Addison-Wesley Professional 2012 (Bradley Irby)
- 编程 Entity Framework: Code First - O'Reilly Media 2011 (Lerman, Julia 和 Miller, Rowan)
- CoffeeScript 小册子 - O'Reilly Media 2012 (MacCaw, Alex)
- JavaScript Web 应用程序 - O'Reilly Media 2011 (MacCaw, Alex)
- Professional ASP.NET MVC 4 - Wrox 2012 (Jon Galloway)
- 理解 AJAX:使用 JavaScript 创建富互联网应用程序 - Pearson 2007 (Joshua Eichorn)
Joshua Eichorn
- LINQ to Entities: 组合谓词 - Colin Meek
- aspnet mvc4 中的 Coffeescript 自定义处理器 - Pieterg
- ASP.NET WebAPI 的 RSS & Atom MediaTypeFormatter - Filip W
- .NET 4.5 WinRT: 从枚举值获取自定义属性 - Matthias Jauernig
- EFCodeFirst: 从本地缓存或数据库获取实体 - Development With A Dot
- ThreadSafeCachedEnumerable -
- 如何同步运行异步 Task
方法? - StackOverflow - C# 随机字符串生成器 - StackOverflow
- 组合两个表达式 (Expression
>) - StackOverflow - 如何创建一个具有连续循环的线程/任务? - StackOverflow
- WCF 服务上的 RESTful CRUD 操作 - CodeProject
- Bitmap 到 BitmapSource - CodeProject
- 最快的 C# 不区分大小写字符串替换 - CodeProject
- 发送 HTML 表单数据 - ASP.NET
- Code First 迁移 - MSDN