目前在AppHarbor中使用Entity Framework Code First的默认设置会出现一些问题,因为EF默认会执行DropCreateDb,而AppHarbor咩有给我们Drop的权限。
目前AppHarbor提供的解决办法是使用这个Nuget package。
然而使用这个package也有个个问题就是这个package里虽然没有明说,但实际上不支持目前最新的EF 4.3.1,因为最新的EF提供的Migrations功能已经和以前不同,已经不会有什么EdmMetadata之类的表。总之解决方案就是老老实实的使用EF 4.1.*
而且这个package还小题大做的用到了WebActivator,个人感觉只要在Application_Start里加代码就好了吧- -
虽然各种不爽总之是能跑起来了-v-
顺便要吐槽的是AppHarbor的文档真是orz啊,比如说了写什么connection string alias在EF code first中用不了啊神马的,实际上是可以的,但是想要加上"MultipleActiveResultSets=True;"的话大概还是要写一些代码的,参考文档吧,我还没试。
1首先是在本机安装git环境,这个大家写过的比较多了,简略一点。
1.1 下载安装msysgit
地址http://code.google.com/p/msysgit/downloads/list
下载最新的“Full installer for official Git for Windows”
最新的msysgit安装过程简略了很多,没有过去那么多选项。全都下一步就ok。
1.2 下载安装tortoisegit,windows下有这个还是比较简单
地址http://code.google.com/p/tortoisegit/downloads/list
最新版据说已经解决了文件名编码的问题。
1.3 VS中安装扩展Git Source Control Provider
这一步不做也成。
2 用github托管源代码
2.1 首先照着这里做
http://help.github.com/win-set-up-git/
前面那些安装过程我们都做过了,从Set Up SSH Keys这一节开始就好。
2.2 确认账户信息配置完毕后,创建自己的代码库。
代码库类型选择默认的public就好,反正版权不值钱-v-
那个Initialize this repository with a README就选上吧,省得自己做一次初始化了。
2.3 在本地某个文件夹clone吧
右键->Git Clone...
Url填入你的代码库的http地址吧,SSH的貌似不行。。。总之大体是这样
2.4 在本地工作目录下尝试新建一个ASP.Net MVC3工程,commit之后push
应该能在github里看到自己提交的代码了。
3 在AppHarbor创建自己的application
去创建就好了,傻瓜式的,暂时不需要各种高级功能,基本上填个名字就ok。。。
4 连接github与AppHarbor
4.1 这里有教程,照做就是
http://blog.appharbor.com/2011/10/13/announcing-github-support
由于刚才选的是public的代码库,所以有关private的内容统统不用理会,真是简单明快呢-v-
顺便说一下,github那边所说的“Create build URL”,实际指的是AppHarbor那边的那个“BUILD URL”那个按钮。那个按钮点击之后会把build的url copy进剪贴板,找个地方粘贴一下就能看到了。那个按钮本身是flash做的,浏览器block的童鞋们注意一下。
4.2 确认效果
如果成功的话,之后的每次向github push应该都会触发一次AppHarbor的build。暂时没有想提交的东西也没关系,可以在刚才github那边点一下那个“Test Hook”。
总之如果成功连接,回到AppHarbor的application后台主页那里,就应该能看到最近的build情况了
Build没有问题的话,点击“Go to your application”,熟悉的Mvc界面就出现啦~\(≧▽≦)/~
我有这么个需求:
项目里想使用Common.Logging来输出log,但并不想固定的依赖log4net或者NLog之类的,所以我不能直接install log4net之类的package。但是运行时当然又需要,所以我要写个build脚本,整体build完了之后把log4net.dll之类的copy到debug下面。
于是问题就来了:我的所有project都没有依赖log4net,所以packages目录下自然就没有log4net.1.2.10咯,那我copy的时候source是啥?
首先想到的自然是Nuget从1.6开始提供的package restore功能,反正我已经自己写脚本了,调用一下NuGet.targets不就好了?
事实证明我图样图森破了。。。 打开NuGet.targets
为毛写死了不许自定义啊。。。没关系,咱改了它
之后在我的脚本里添加如下内容
<Project ToolsVersion="4.0" DefaultTargets="Buid" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<RestorePackages>true</RestorePackages>
<PackagesConfig>$([System.IO.Path]::Combine($(MSBuildProjectDirectory), "MyComany.MyProduct.MySolution.Packages.config"))</PackagesConfig>
</PropertyGroup>
<Import Project="..\.nuget\nuget.targets" />
<!--Build All-->
<Target Name="Buid">
<CallTarget Targets="RestorePackages"/>
</Target>
</Project>
结果一运行,报错说我的"MyComany.MyProduct.MySolution.Packages.config"找不到。
我检查了好几遍路径都没错啊~~~结果把文件重命名为packages.config,成功了。。。
最后看了一下帮助(nuget help install)
Installs a package using the specified sources. If no sources are specified, all
sources defined in %AppData%\NuGet\NuGet.config are used. If NuGet.config spec
ifies no sources, uses the default NuGet feed.
Specify the id and optionally the version of the package to install. If a
path to a packages.config file is used instead of an id, all the packages
it contains are installed.
你妹啊!为啥只认packages.config啊!
Task的API设计确实有很多令人迷惑的地方,所以真的非常感谢Stephen Toub的这篇FAQ。节译其中的主要部分。
1.Q:我应该什么时候使用Task.Start?
A:Start实例方法可以用在且只能用在task处在Created状态(也就是task.Status返回TaskStatus.Created),而唯一能使task处在这一状态的方式就是使用Task的public构造器
2.Q:我有一个由Task.Run / Task.ContinueWith / Task.Factory.StartNew / TaskCompletionSource / 异步方法创建的task,我能不能对其调用Start方法?
A:如上所述,不能。会抛异常的。以上任意一个方法创建的task都意味着task不再处在Created状态,而是其他状态例如TaskStatus.WaitingForActivation、TaskStatus.Running、TaskStatus.RanToCompletion
3.Q:Start方法实际上做了什么?
A:它把task放入目标TaskScheduler(无参的Start方法意味着目标TaskScheduler为TaskScheduler.Current)。当你使用构造器创建一个task,它处于非活动状态,也就是说没有被放入任何一个TaskScheduler,因而没人会运行它。如果你不调用Start方法,它永远不会被放入队列,所以永远不会完成。想让task被执行,就需要把它放入队列,这样调度器会在它认为合适的时机运行你的task。Start方法会对task对象做一些变化(例如修改状态为WaitingToRun),之后调用目标TaskScheduler的QueueTask方法将其放入队列,从此时开始,task未来的运行就交由调度器处理,调度器最终会调用TryExecuteTask方法执行你的task。
4.Q:我能对同一个task多次调用Start方法么?
A:不能。一个task从Created状态变到别的状态这个行为只能出现一次,Start方法就会导致这个行为,所以Start方法也只能被调用一次。多次调用只会导致异常。Start方法引入了同步机制来保证task对象处在一致性的状态,所以即使多次并发的调用Start方法,也只有其中的一次调用会成功。
5.Q:Task.Start和Task.Factory.StartNew有什么不同?
A:Task.Factory.StartNew是一种简略的写法,实际就是构造一个task然后Start,所以如下的代码
var t = Task.Factory.StartNew(someDelegate);
和如下的代码从效果上是相同的
var t = new Task(someDelegate);
t.Start();
但从性能上来说,前者更好。如#3中所说,Start方法引入了同步机制来保证该task在Start之前尚未Start,也不会被并发的多次Start。与之相对的,StartNew方法知道不可能有其他人Start这个task因为这个引用尚未返回给任何人,所以StartNew方法无需引入同步机制。
6.Q:我听说调用Task.Result也可以开始一个task?
A:没这回事。当一个task处在Created状态,只有两种可能性使其变化到其他状态。
1. 构造task时传入了一个CancellationToken,当task还在Created状态时有了取消请求,那么task会变化为Canceled状态。
2. 有人调用了Start方法
调用Result不属于上述两种之一。当你对一个还处在Created状态的task调用Wait方法或者Result,调用会被阻塞。直至有人调用了Start,之后balabala,最终task完成了,被阻塞的调用才会完成。
你以为调用Result可能会开始一个task,那是不对的。实际上那倒有可能导致task被“内联”的执行。当task已经被放入TaskScheduler的队列,它也许并未开始,依然躺在队列里,当你对这种task调用Result,运行时可能会尝试内联的执行这个task(也就是说在你的调用线程上执行task),而不会等某个其他线程啥时候闲下来有空。从内部来说,就是Result内部也许会调用TaskScheduler的TryExecuteTaskInline方法,当然以上所说的“也许”都取决于TaskScheduler想怎么执行你的请求。
7. Q:我设计了一个公开的API要返回一个task,我应该返回一个尚未开始的task么?
A:不要这么做。(这里把这个问题和#1、#2区别对待是因为#1和#2是真的想创建一个task之后可能选择不开始它。大家不要以为非得违背设计意图的开始一个不想开始的task之后返回)
那么,通常的来讲如果你调用的是一个同步方法,那个方法肯定是你一调用就开始执行的。那么在返回一个task对象的异步方法的场合,你可以认为task就是未来终将会完成的异步方法,那并不改变一个事实:通过这个方法的调用,相应的操作应该已经开始执行了。因此,如果你返回一个尚未开始的task从语义上来讲就很奇怪。
所以如果你在方法内部使用构造器创造了一个task,那么在返回它之前记得调用Start,否则可能引起死锁或者类似的情况,因为消费者会期待着你返回的task终将完成,但如果你根本没开始这个task那它当然也就无从完成。有些框架甚至允许你通过一个方法或者委托神马的来指定一个检查,当你启用了这个检查,框架会检查返回的task的状态,如果尚处在Created状态会抛异常。
8. Q:说了半天我到底应不应该首先调用构造器创造一个task然后调Start呢?
A:对于大多数场合,你蛮好还是直接调用Task.Run或者TaskScheduler.StartNew吧,如果你的需求仅仅是让调度器帮你异步执行一段委托。这样不仅代码少,性能也好(如#5所述),而且减少了出错的几率(比如你忘了调Start神马的)。
当然构造器+Start方法也有其用武之地。比如你派生了自己的Task类型,那你就需要Start方法来真正把你的对象放入队列。再来看一个高级点例子:如果你想要在task的委托里使用这个task对象
Task theTask = null;
theTask = Task.Run(() => Console.WriteLine(“My ID is {0}.”, theTask.Id));
发现破绽了么?这儿有个竞态。当你调用Task.Run时,一个新的task对象被创建出来并被放入TaskScheduler的队列,如果当时线程池很闲,也许立刻就会有个线程来执行这段委托,这个线程会访问由主线程创建的theTask对象,从而存在一个竞态。想避免这种情况,只要把构造和开始分开执行就好了
Task theTask = null;
theTask = new Task(() =>Console.WriteLine(“My ID is {0}.”, theTask.Id));
theTask.Start(TaskScheduler.Default);
现在就可以保证在委托线程访问theTask对象之前主线程已经完成了对它的赋值
WPF纯新手,之前拿WPF当WinForm一样的用过一两次,那时候对WPF是啥完全没有加以了解,就当WPF=WinForm的background code+xaml版的ASP.NET
这次准备开始做一个WPF项目,领导希望xaml和代码尽可能的分离,才找了本《WPF 4 Unleashed》看了下,然后简单了解了下Prism和MVVMLight就准备动手啦~~
貌似stackoverflow上对MVVMLight还比较赞,就准备用这个,结果第一次用就orz了,写出一点初步的心得给组里其他WPF初学者看一下,也请园子里的高手多指教。
■安装相关
我用的安装包,一切安装顺利,结果尝试新建一个MVVMLight Application的时候说项目模板(ProjectForTemplate.csproj) 找不到。
解决办法是到报错那个目录(C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ProjectTemplatesCache\CSharp\Windows\Mvvm\MvvmLight.WPF4.zip)下把MvvmLight.WPF4.csproj重命名就好了-v-
顺便说一下我也下了手动安装的那个zip包,好像文件名是没有问题的,下次尝试手动安装好了
之后是code snippets,好像不会像prop之类的那样有智能感知啊?从code snippets manager那里也确实找到了,在Snippets\CSharp下面,是不是应该挪到Visual C#下面?不知道了。。。求帮助
■ ViewModel相关生成这种代码是要闹哪样啊 囧
throw new NotImplementedException();
// Update bindings, no broadcast
//RaisePropertyChanged(UserIDPropertyName);
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
//RaisePropertyChanged(UserIDPropertyName, oldValue, value, true);
我还没有理解所谓broadcast在这里做什么用,是一种类似于总线的设计?但是单从API设计来看我总会觉得这两个方法有一个内部调用关系的,于是我发现这两个方法都可以重载的时候我好惊讶- -
另外为了写个属性弄出这么一堆代码,也没给生成个region神马的看起来实在很头疼。。。就不能参考那个神马NotifyWaver(名字好像更长些?没记住。。。)的做法编译后织入么
■ Messenger相关这个才是我真正想吐槽的地方啊!
为神马Messenger比IMessenger公开的方法多啊!虽然这个也说得过去,但ViewModelBase里的MessengerInstance为神马是IMessenger类型啊!这样的话不是逼着我用Messenger.Default么!提供MessengerInstance有咩用啊!
然后Send方法还可以指定Target。。。我看例子中都是指定了一个View。。。这样ViewModel怎么和View分离啊!囧死了
最后为了一个Navigation要写这样的代码。。。
某ViewModel的某Command
Messenger.Default.Send("XXXX", "NavigationRequest");
某View
, action =>
{
if (action.Equals("XXXX",
StringComparison.InvariantCultureIgnoreCase))
{
_mainFrame.NavigationService.Navigate(
new Uri("/Views/DashBoard.xaml", UriKind.Relative));
}
});
要用一个字符串作"NavigationRequest" 为token。。。而且可以指定token的这个Send方法还不是IMessenger里的。。。
呼,就到这里吧~








