选择315这天分享一个好框架-ServiceFabric,它于昨天正式开源了! 微软的 Azure Service Fabric 的官方博客在2017.3.24日发布了一篇博客 Service Fabric .NET SDK goes open source ,介绍了社区呼声最高的 Service Fabric 开源的情况以及当前的情况,当时开源了 Service Fabric的.NET SDK 部分,社区一直在期盼着 Service Fabric 的正式开源,经过了一年漫长的等待,2018年3月14日微软终于开源了 Service Fabric ,而且是以 MIT 许可下开放源代码,在官方博客宣布 https://blogs.msdn.microsoft.com/azureservicefabric/2018/03/14/service-fabric-is-going-open-source。 目前微软在 Github 上的开源地址是 https://github.com/Microsoft/service-fabric,目前的代码构建适用于 Linux 的 Service Fabric ,运行基本测试,有问题可以在上面提交 issue 和 PR 了,Windows 构建环境以及完整的 CI 环境还没有迁移过来。Windows 内部为 Service Fabric 开发了将近十年的内部服务,其中大部分时间都是微软内部平台,比如 Office365,Azure Stack 平台等,这意味着我们有近十年的内部微软工具可以在迁移之前完成迁移和流程细化,逐步全部开源,以后全部开发都在开源模式下进行开发工作。 微软去年漫长的一年时间里也开放了非常多的代码,包括包括 Reliable Services,Reliable Actors 和 ASP.NET Core 集成库,Azure 基础架构服务以及 Azure SQL DB,Azure Cosmos DB 和 Cortana 等大型解决方案都在使用 Service Fabric 构建。 Service Fabric 会带来如下好处: 支持创建无状态和有状态的微服务,通过云平台来伸缩他们,以应对高复杂度、低延迟、数据密集的情况 通过应用程序级别的感知和洞察,为微服务带来编排和自动化的优势 解决分布式系统诸如状态管理这样的难点,为开发人员提供应用程序生命周期管理的能力以便随着业务的增长无需重构系统架构 相关工具会集成到 Visual Studio 中,也会提供相应命令行工具,以便开发人员能够快速和轻易地上手 同时支持.NET和Java,这个特性特别适合目前国内原来很多投资于 .NET 平台。 那么接下来,我们主要来详细看下Service Fabric是什么?有哪些特性? […]
View Details什么是容器 容器是一种将应用程序包装到其自身隔离空间内的方法。 位于容器中的应用不了解该容器外存在的所有其他应用程序或进程。 应用程序成功运行所需的所有依赖项也存在于此容器内。 无论容器移动到何处,应用程序都将始终得到满足,因为应用程序与其运行所需的一切都已绑定在一起。 这就好像是一个厨房。 我们打包所有的电器和家具、锅碗瓢盆、洗洁精和毛巾。 这便是我们的容器 我们现在可以带着这个容器,将它放在任何喜欢的入住公寓中,厨房还会是这个厨房。 我们所需做的全部工作就是为它接通水电,然后我们便可以立即开始烹饪(因为我们拥有所有需要的器具!) 容器在很大程度上就像是这个厨房。 可以有不同类型的房间以及许多相同类型的房间。 重要的一点是容器与其所需的一切内容打包在一起。 在此处观看简短概述:基于 Windows 的容器:使用企业级控制的现代应用开发。 容器基础知识 容器是独立的、资源受控制的和可移植的运行时环境,在主机或虚拟机上运行。 在容器中运行的应用程序或进程与所有需要的依赖项和配置文件打包在一起;在它看来,容器之外似乎没有任何其他进程在运行。 容器的主机为容器预配一组资源,且容器只会使用这些资源。 在容器看来,除了已经为其提供的资源之外,不存在其他资源,因此它不能接触到可能已为相邻容器预配的资源。 在你开始创建和使用 Windows 容器时,以下关键概念将会很有用。 容器主机:使用 Windows 容器功能配置的物理或虚拟计算机系统。 容器主机将运行一个或多个 Windows 容器。 容器映像:在对容器文件系统或注册表进行修改时(如软件安装),将在沙盒中捕获这些修改。 在许多情况下,你可能希望捕获此状态,以便可以创建继承这些更改的新容器。 这就是映像的本质:一旦容器停止,你便可以放弃该沙盒,或者可以将其转换为新的容器映像。 例如,让我们想象你已从 Windows Server Core 操作系统映像部署一个容器。 然后你将 MySQL 安装到此容器中。 从此容器创建新映像将充当该容器的可部署版本。 此映像将只包含所做的更改 (MySQL),但是将充当容器操作系统映像之上的一个层。 沙盒:容器启动后,将在此“沙盒”层中捕获所有的写入操作,如文件系统修改、注册表修改或软件安装。 容器操作系统映像:从映像部署容器。 容器操作系统映像是可能组成容器的许多映像层中的第一层。 此映像提供操作系统环境。 容器操作系统映像是不可变的。 也就是说,不能对其进行修改。 容器存储库:每次创建容器映像时,容器映像及其依赖项都会存储在本地存储库中。 这些映像可以在容器主机上重复使用多次。 容器映像还可以存储在公共或私有注册表(如 DockerHub)中,以便可以在许多不同的容器主机上使用它们。 对于熟悉虚拟机的人员而言,容器可能具有令人难以置信的相似性。 容器在操作系统上运行、具有文件系统,并且可以通过网络访问,就像它是物理或虚拟计算机系统一样。 话虽如此,但容器背后的技术和概念与虚拟机有很大不同。 Microsoft Azure 专家 Mark Russinovich 有一篇精彩的博客文章详述了这些差异。 Windows 容器类型 Windows 容器包括两个不同的容器类型或运行时。 Windows Server 容器 – 通过进程和命名空间隔离技术提供应用程序隔离。 Windows Server 容器与容器主机和该主机上运行的所有容器共享内核。 这些容器不提供敌对安全边界,不应该用于隔离不受信任的代码。 由于共享内核空间,这些容器要求具有相同的内核版本和配置。 Hyper-V 隔离 – 通过在高度优化的虚拟机中运行每个容器,在由 Windows Server 容器提供的隔离上扩展。 在此配置中,容器主机的内核不与相同主机上的其他容器共享。 这些容器旨在托管敌对多租户,并且具有与虚拟机相同的安全保证。 由于这些容器与主机或主机上的其他容器不共享内核,它们可运行(与受支持的版本)采用不同版本和配置的内核 – 例如 Windows […]
View Details1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉。事件总线是对发布-订阅模式的一种实现。它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解耦的目的。 我们来看看事件总线的处理流程: 了解了事件总线的基本概念和处理流程,下面我们就来分析下如何去实现事件总线。 2.回归本质 在动手实现事件总线之前,我们还是要追本溯源,探索一下事件的本质和发布订阅模式的实现机制。 2.1.事件的本质 我们先来探讨一下事件的概念。都是读过书的,应该都还记得记叙文的六要素:时间、地点、人物、事件(起因、经过、结果)。 我们拿注册的案例,来解释一下。 用户输入用户名、邮箱、密码后,点击注册,输入无误校验通过后,注册成功并发送邮件给用户,要求用户进行邮箱验证激活。 这里面就涉及了两个主要事件: 1,注册事件:起因是用户点击了注册按钮,经过是输入校验,结果是是否注册成功。 2,发送邮件事件:起因是用户使用邮箱注册成功需要验证邮箱,经过是邮件发送,结果是邮件是否发送成功。 其实这六要素也适用于我们程序中事件的处理过程。开发过WinForm程序的都知道,我们在做UI设计的时候,从工具箱拖入一个注册按钮(btnRegister),双击它,VS就会自动帮我们生成如下代码: void btnRegister_Click(object sender, EventArgs e) { // 事件的处理 } 其中object sender指代发出事件的对象,这里也就是button对象;EventArgs e 事件参数,可以理解为对事件的描述 ,它们可以统称为事件源。其中的代码逻辑,就是对事件的处理。我们可以统称为事件处理。 说了这么多,无非是想透过现象看本质:事件是由事件源和事件处理组成。 2.2. 发布订阅模式 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。 ——发布订阅模式 发布订阅模式主要有两个角色: 1,发布方(Publisher):也称为被观察者,当状态改变时负责通知所有订阅者。 2,订阅方(Subscriber):也称为观察者,订阅事件并对接收到的事件进行处理。 发布订阅模式有两种实现方式: 1,简单的实现方式:由Publisher维护一个订阅者列表,当状态改变时循环遍历列表通知订阅者。 2,委托的实现方式:由Publisher定义事件委托,Subscriber实现委托。 总的来说,发布订阅模式中有两个关键字,通知和更新。 被观察者状态改变通知观察者做出相应更新。 解决的是当对象改变时需要通知其他对象做出相应改变的问题。 如果画一个图来表示这个流程的画,图形应该是这样的: 3 实现发布订阅模式 相信通过上面的解释,对事件和发布订阅模式有了一个大概的印象。都说理论要与实践相结合,所以我们还是动动手指敲敲代码比较好。 我将以『观察者模式』来钓鱼这个例子为基础,通过重构的方式来完善一个更加通用的发布订阅模式。 先上代码: /// <summary > /// 鱼的品类枚举 /// </summary > public enum FishType { 鲫鱼, 鲤鱼, 黑鱼, 青鱼, 草鱼, 鲈鱼 } 钓鱼竿的实现: /// <summary > /// 鱼竿(被观察者) /// </summary > public class FishingRod { public delegate void FishingHandler(FishType type); //声明委托 public event FishingHandler FishingEvent; //声明事件 public void ThrowHook(FishingMan man) { Console.WriteLine("开始下钩!"); //用随机数模拟鱼咬钩,若随机数为偶数,则为鱼咬钩 if (new Random().Next() % 2 == 0) { var type = (FishType) new Random().Next(0, 5); Console.WriteLine("铃铛:叮叮叮,鱼儿咬钩了"); if (FishingEvent != null) FishingEvent(type); } } } 垂钓者: /// <summary > /// 垂钓者(观察者) /// </summary > public class FishingMan { public FishingMan(string name) { Name = name; } public string Name { get; set; } public int FishCount { get; set; } /// <summary > /// 垂钓者自然要有鱼竿啊 /// </summary > public FishingRod FishingRod { get; set; } public void Fishing() { this.FishingRod.ThrowHook(this); […]
View Details一、组件 创建出来的对象需要从组件中来获取,组件的创建有如下4种(延续第一篇的Demo,仅仅变动所贴出的代码)方式: 1、类型创建RegisterType AutoFac能够通过反射检查一个类型,选择一个合适的构造函数,创造这个对象的实例。主要通过RegisterType<T>() 和 RegisterType(Type) 两个方法以这种方式建立。 ContainerBuilder使用 As() 方法将Component封装成了服务使用。
|
1 2 |
builder.RegisterType<AutoFacManager>(); builder.RegisterType<Worker>().As<IPerson>(); |
2、实例创建
|
1 |
builder.RegisterInstance<AutoFacManager>(new AutoFacManager(new Worker())); |
单例 提供示例的方式,还有一个功能,就是不影响系统中原有的单例:
|
1 |
builder.RegisterInstance(MySingleton.GetInstance()).ExternallyOwned(); //将自己系统中原有的单例注册为容器托管的单例 |
这种方法会确保系统中的单例实例最终转化为由容器托管的单例实例。 3、Lambda表达式创建 Lambda的方式也是Autofac通过反射的方式实现
|
1 2 |
builder.Register(c => new AutoFacManager(c.Resolve<IPerson>())); builder.RegisterType<Worker>().As<IPerson>(); |
4、程序集创建 程序集的创建主要通过RegisterAssemblyTypes()方法实现,Autofac会自动在程序集中查找匹配的类型用于创建实例。
|
1 2 |
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()); //在当前正在运行的程序集中找 builder.RegisterType<Worker>().As<IPerson>(); |
5、泛型注册 泛型注册通过RegisterGeneric() 这个方法实现,在容易中可以创建出泛型的具体对象。
|
1 2 3 4 5 6 |
//泛型注册,可以通过容器返回List<T> 如:List<string>,List<int>等等 builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>)).InstancePerLifetimeScope(); using (IContainer container = builder.Build()) { IList<string> ListString = container.Resolve<IList<string>>(); } |
6、默认的注册 如果一个类型被多次注册,以最后注册的为准。通过使用PreserveExistingDefaults() 修饰符,可以指定某个注册为非默认值。
|
1 2 3 4 5 6 7 8 9 |
ContainerBuilder builder = new ContainerBuilder(); builder.RegisterType<AutoFacManager>(); builder.RegisterType<Worker>().As<IPerson>(); builder.RegisterType<Student>().As<IPerson>().PreserveExistingDefaults(); //指定Student为非默认值 using (IContainer container = builder.Build()) { AutoFacManager manager = container.Resolve<AutoFacManager>(); manager.Say(); //输出我是一个工人 } |
如果不使用PreserveExistingDefaults(),那么将输出“我是一个学生”。 二、服务 Autofac有三种典型的方式区分服务,同一个服务的不同实现可以由类型,名称和键区分。 1、类型 类型是描述服务的基本方法
|
1 |
builder.RegisterType<Worker>().As<IPerson>(); //IPerson类型的服务和Worker的组件连接起来,这个服务可以创建Worker类的实例 |
并且上面的服务在自动装备中也有效
|
1 |
AutoFacManager manager = container.Resolve<AutoFacManager>(); |
2、名字 服务可以进一步按名字识别。使用这种方式时,用 Named()注册方法代替As()以指定名字:
|
1 |
builder.RegisterType<Worker>().Named<IPerson>("worker"); |
使用Name可以检索服务创建实例:
|
1 |
IPerson p = container.ResolveNamed<IPerson>("worker"); |
ResolveNamed()只是Resolve()的简单重载,指定名字的服务其实是指定键的服务的简单版本。 3、键 有Name的方式很方便,但是值支持字符串,但有时候我们可能需要通过其他类型作键。 例如,使用枚举作为key:
|
1 |
public enum DeviceState { Worker, Student } |
使用key注册服务,通过Keyed<T>()方法:
|
1 |
builder.RegisterType<Student>().Keyed<IPerson>(DeviceState.Student); |
显式检索 使用key检索服务以创建实例,通过ResolveKeyd()方法:
|
1 |
IPerson p = container.ResolveKeyed<IPerson>(DeviceState.Student); |
ResolveKeyd()会导致容器被当做 Service Locator使用,这是不被推荐的。应该使用IIndex type替代。 IIndex索引 Autofac.Features.Indexed.IIndex<K,V>是Autofac自动实现的一个关联类型。component可以使用IIndex<K,V>作为参数的构造函数从基于键的服务中选择需要的实现。
|
1 2 3 4 5 6 7 |
builder.RegisterType<Student>().Keyed<IPerson>(DeviceState.Student); using (IContainer container = builder.Build()) { IIndex<DeviceState, IPerson> IIndex = container.Resolve<IIndex<DeviceState, IPerson>>(); IPerson p = IIndex[DeviceState.Student]; p.Say(); //输出我是一个学生 } |
IIndex中第一个泛型参数要跟注册时一致,在例子中是DeviceState枚举。其他两种注册方法没有这样的索引查找功能,这也是为什么设计者推荐Keyed注册的原因之一。 三、自动装配 从容器中的可用服务中选择一个构造函数来创造对象,这个过程叫做自动装配。这个过程是通过反射实现的,所以实际上容器创造对象的行为比较适合用在配置环境中。 1、选择构造函数 Autofac默认从容器中选择参数最多的构造函数。如果想要选择一个不同的构造函数,就需要在注册的时候就指定它。
|
1 |
builder.RegisterType(typeof(Worker)).UsingConstructor(typeof(int)); |
这种写法将指定调用Worker(int)构造函数,如该构造函数不存在则报错。 2、额外的构造函数参数 有两种方式可以添加额外的构造函数参数,在注册的时候和在检索的时候。在使用自动装配实例的时候这两种都会用到。 注册时添加参数 使用WithParameters()方法在每一次创建对象的时候将组件和参数关联起来。
|
1 2 |
List<NamedParameter> ListNamedParameter = new List<NamedParameter>() { new NamedParameter("Id", 1), new NamedParameter("Name", "张三") }; builder.RegisterType<Worker>().WithParameters(ListNamedParameter).As<IPerson>(); |
在检索阶段添加参数 在Resolve()的时候提供的参数会覆盖所有名字相同的参数,在注册阶段提供的参数会覆盖容器中所有可能的服务。 3、自动装配 至今为止,自动装配最大的作用就是减少重复配置。许多相似的component无论在哪里注册,都可以通过扫描使用自动装配。
|
1 |
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).As<IPerson>(); |
在需要的时候,依然可以创建指定的构造函数创建指定的类。
|
1 |
builder.Register(c => new Worker(2,"关羽")); |
四、程序集扫描 1、扫描 Autofac可以使用约定在程序集中注册或者寻找组件。 Autofac可以根据用户指定的规则在程序集中注册一系列的类型,这种方法叫做convention-driven registration或者扫描。
|
1 |
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Manager")); |
[…]
View Details最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。 十年河东十年河西,莫欺少年穷 学无止境,精益求精 今天有点胡思乱想,想遍历MVC Model的属性并取值: 这个方法还是很简单的,通过反射即可遍历属性,我总结的方法如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
namespace WeiXinApi.CommonCS { public class ForeachClass { /// <summary> /// C#反射遍历对象属性 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="model">对象</param> public static void ForeachClassProperties<T>(T model) { Type t = model.GetType(); PropertyInfo[] PropertyList = t.GetProperties(); foreach (PropertyInfo item in PropertyList) { string name = item.Name; object value = item.GetValue(model, null); } } } } |
下面我们来简单测试下: 新建Model如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class AddressInfo { public int Id { get; set; } public string userName { get; set; } public string userTel { get; set; } public string Addressdetail { get; set; } public int isMoren { get; set; } public AddressInfo() { Id = 1; userName = "陈卧龙"; userTel = "1813707015*"; Addressdetail = "江苏省苏州市工业园区国际科技园"; isMoren = 1; } } |
调用如下:
|
1 2 3 4 5 6 7 8 9 |
public partial class index : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //Response.Redirect("/Home/Login"); AddressInfo model = new AddressInfo(); ForeachClass.ForeachClassProperties<AddressInfo>(model); } } |
测试结果如下: 经过测试,我们可以得到对象的各个属性及对应的值、 其实这块内容输入C# 反射系列,小弟也是误打误撞,撞入了C# 反射,索性每天学一点 from:https://www.cnblogs.com/chenwolong/p/fanshe.html
View Details|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public class PP { public string a { get; set; } public string b { get; set; } public string c { get; set; } } class Program { static void Main(string[] args) { Hashtable ht = new Hashtable(); ht.Add("a", "utf8"); ht.Add("b", "xxxx"); ht.Add("c", "xxxx"); PP config = new PP(); PropertyInfo[] propertys = config.GetType().GetProperties(); foreach (PropertyInfo property in propertys) { for (int i = 0; i < ht.Count; i++) { property.SetValue(config, ht[property.Name].ToString(), null); } } Console.WriteLine(config.a+"\t"+config.b); Console.ReadLine(); } } |
from:https://www.cnblogs.com/yanglang/p/6830982.html
View Details解决方案:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<VSTemplate Version="2.0.0" Type="ProjectGroup" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"> <TemplateData> <Name>DD373.Demo</Name> <Description>a DD373 Demo 16</Description> <Icon>__TemplateIcon.jpg</Icon> <ProjectType>CSharp</ProjectType> </TemplateData> <TemplateContent> <ProjectCollection> <ProjectTemplateLink ProjectName="$projectname$.Access" CopyParameters="true">DD373.Demo.Access\MyTemplate.vstemplate</ProjectTemplateLink> <ProjectTemplateLink ProjectName="$projectname$.Entity" CopyParameters="true">DD373.Demo.Entity\MyTemplate.vstemplate</ProjectTemplateLink> </ProjectCollection> </TemplateContent> </VSTemplate> |
其中一个解决方案:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<VSTemplate Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project"> <TemplateData> <Name>DD373.Demo.Access</Name> <Description>Access</Description> <ProjectType>CSharp</ProjectType> <ProjectSubType> </ProjectSubType> <SortOrder>1000</SortOrder> <CreateNewFolder>true</CreateNewFolder> <DefaultName>DD373.Demo.Access</DefaultName> <ProvideDefaultName>true</ProvideDefaultName> <LocationField>Enabled</LocationField> <EnableLocationBrowseButton>true</EnableLocationBrowseButton> <Icon>__TemplateIcon.jpg</Icon> <PreviewImage>__PreviewImage.jpg</PreviewImage> </TemplateData> <TemplateContent> <Project TargetFileName="DD373.Demo.Access.csproj" File="DD373.Demo.Access.csproj" ReplaceParameters="true"> <Folder Name="Properties" TargetFolderName="Properties"> <ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem> </Folder> <ProjectItem ReplaceParameters="true" TargetFileName="User.cs">User.cs</ProjectItem> </Project> </TemplateContent> </VSTemplate> |
View Details
若要了解有关 Visual Studio 2017 RC 的最新文档,请参阅 Visual Studio 2017 RC 文档。 在对模板进行实例化时,您可以通过模板的参数,替换模板的关键部分的值,如类名和命名空间。 当用户在“新建项目”或“添加新项”对话框中单击“确定”时,这些参数将由后台运行的模板向导替换。 声明和启用模板参数 模板参数以 $parameter$ 格式进行声明。 例如: $safeprojectname$ $guid1$ $guid5$ 启用模板中的参数替换 在模板的 .vstemplate 文件中,定位到与要为其启用参数替换的项对应的 ProjectItem 元素。 将 ProjectItem 元素的 ReplaceParameters 特性设置为 true。 在项目项的代码文件中,在合适的位置包括参数。 例如,下面的参数指定用于文件中的命名空间的安全项目名称:
|
1 |
namespace $safeprojectname$ |
保留的模板参数 下表列出了可供所有模板使用的保留的模板参数。 说明 模板参数区分大小写。 Parameter 描述 clrversion 公共语言运行时 (CLR) 的当前版本。 GUID [1-10] 用于替换项目文件中的项目 GUID 的 GUID。 最多可以指定 10 个唯一的 GUID(例如,guid1))。 itemname 用户在添加新项对话框中提供的名称。 machinename 当前的计算机名称(例如,Computer01)。 projectname 用户在新建项目对话框中提供的名称。 registeredorganization HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOrganization 中的注册表项值。 rootnamespace 当前项目的根命名空间。 此参数仅适用于项目模板。 safeitemname 用户在“添加新项”对话框中提供的名称,名称中移除了所有不安全的字符和空格。 safeprojectname 用户在“新建项目”对话框中提供的名称,名称中移除了所有不安全的字符和空格。 time 以 DD/MM/YYYY 00:00:00 格式表示的当前时间。 SpecificSolutionName 解决方案的名称。 当“创建解决方案的目录”被选中,SpecificSolutionName 具有解决方案的名称。 当“创建解决方案的目录”没有被选中,SpecificSolutionName是空。 userdomain 当前的用户域。 username 当前的用户名。 webnamespace 当前网站的名称。 在 Web 窗体模板中使用此参数以确保类名称是唯一的。 如果网站位于 Web 服务器的根目录下,则此模板参数将解析为 Web 服务器的根目录。 […]
View Details若要了解有关 Visual Studio 2017 RC 的最新文档,请参阅 Visual Studio 2017 RC 文档。 指定多项目模板中一个项目的 .vstemplate 文件的路径。 语法
|
1 2 3 |
<ProjectTemplateLink ProjectName="Name"> PathToTemplateFile </ProjectTemplateLink> |
特性和元素 以下各部分描述了特性、子元素和父元素。 特性 特性 描述 ProjectName 可选特性。 指定多项目模板中每一个项目的名称。 新项目对话框中不能向单个项目分配名称。 CopyParameters 使主要组模板中的所有变量可复制到每个链接模板。 链接模板中的参数具有前缀 "$ext_*$"。 例如,如果在父组模板参数$projectname$具有值exampleproject1 则轮到,当模板链接获取又要执行,它将获取参数$ext_projectname$,这是一份$projectname$父组模板中的参数。 这使链接模板能够共享一些只能在父组模板中方便地创建的公用参数。 此特性为可选特性,未包含此特性时,它将自动默认为 false。 在 Visual Studio 2013 Update 2 中引入。 若要引用正确的产品版本,请参阅引用程序集提供的 Visual Studio 2013 SDK Update 2。 父元素 元素 描述 ProjectCollection 指定多项目模板的组织和内容。 SolutionFolder 对多项目模板中的项目进行分组。 文本值 需要一个文本值。 此文本指定模板的 .vstemplate 文件的路径。 多项目模板用作两个或多个项目的容器。 ProjectTemplateLink 元素用于指定模板中一个项目的 .vstemplate 文件的位置。 对于多项目模板中的每个项目,此模板的 .vstemplate 文件中都含有一个对应的 ProjectTemplateLink 元素。 有关多项目模板的详细信息,请参阅如何︰ 创建多项目模板。 此示例演示一个简单的多项目 .vstemplate 根文件。 在此示例中,模板包含两个项目:My Windows Application 和 My Class Library。ProjectName 元素的 ProjectTemplateLink 特性可为 Visual Studio 设置要分配给此项目的名称。 如果不存在 ProjectName 特性,则会使用 .vstemplate 文件的名称作为项目名称。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<VSTemplate Version="3.0.0" Type="ProjectGroup" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"> <TemplateData> <Name>Multi-Project Template Sample</Name> <Description>An example of a multi-project template</Description> <Icon>Icon.ico</Icon> <ProjectType>VisualBasic</ProjectType> </TemplateData> <TemplateContent> <ProjectCollection> <ProjectTemplateLink ProjectName="My Windows Application"> WindowsApp\MyTemplate.vstemplate </ProjectTemplateLink> <ProjectTemplateLink ProjectName="My Class Library" CopyParameters="true"> ClassLib\MyTemplate.vstemplate </ProjectTemplateLink> </ProjectCollection> </TemplateContent> </VSTemplate> |
from:https://msdn.microsoft.com/zh-cn/library/ms171398.aspx
View Details本文分2部分 第一为自定义多项目模板 第二为vs add-in开发 效果图 1.自定义模板 2. 工具菜单 3.窗口 4.工程 5.文件 … 一. 多项目模板 单项目模板做起来很简单 选中一个项目在文件一栏中选中导出模板 然后选择项目模板 在最后一项向导会给出你的输出路径,一般都是系统的用户文档路径+\Visual Studio 2010\My Exported Templates 在对应目录下会生成你对应的项目模板压缩包 我们生成2个项目的模板文件 然后做一个多项目模板 我们解压2个模板文件并且放进一个新建的名称为MaoyaTemplates的文件夹 剪切到Visual Studio 2010\Templates\ProjectTemplates路径下 新建模板文件MyTemplate.vstemplate 根据要定义的模板内容 修改文件 然后将整个文件夹压缩成zip文件即可 在TemplateData可以定义一些自己需要的信息 例如icon定义你的模板图标 把图标文件放在相对路径即可 然后重新打开vs 即可看到刚才作成的模板 打开以后就是定义的2个demo工程 相当简单 这样就不用每次来新项目都去copy代码了 二 vs插件 概念性的东西可以参考 http://msdn.microsoft.com/zh-cn/library/bb384200.aspx vs插件可以帮助或者优化你在vs开发过程的大部分窗口 它可以针对文件 针对项目 针对窗口 甚至针对不同的后缀做不同的处理 下面图文+代码介绍开发步骤(vs2010) 选择插件项目 进入向导根据自己的场景选择即可 中间向导过程略过 最后一步 完成向导后 默认工程框架如下 最关键的就是connect.cs文件 Connect 继承了2个类 IDTExtensibility2, IDTCommandTarget IDTExtensibility2 包含在实现接口时用作事件的方法。 每当发生影响某个外接程序的事件时(如加载或卸载该外接程序时)以及对该外接程序进行任何更改时,Visual Studio 都会调用这些方法。 IDTCommandTarget 接口使开发者得以在环境中实现命名命令。 并且以定义命令状态或执行命令。 每个方法的描述 中文版可以参考msdn http://msdn.microsoft.com/zh-cn/library/extensibility.idtextensibility2.aspx http://msdn.microsoft.com/zh-cn/library/envdte.idtcommandtarget.aspx 其中我们作为入门开发 需要关注得的是 OnConnection 为IDTExtensibility2的 main 方法,这是因为每次加载外接程序时都会调用该方法。 该方法为外接程序在加载时的入口点,因此可以将要在外接程序启动时运行的任何代码放置在此处(或调用任何其他函数)。 1 2 3 4 5 6 void OnConnection( Object Application, ext_ConnectMode ConnectMode, Object […]
View Details