我正在使用Topshelf来托管用C#编写的Windows服务,现在我想编写一些集成测试.我的初始化代码保存在启动器类中,如下所示:
public class Launcher
{
private Host host;
/// <summary>
/// Configure and launch the windows service
/// </summary>
public void Launch()
{
//Setup log4net from config file
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(DEFAULT_CONFIG));
//Setup Ninject dependency injection
IKernel kernel = new StandardKernel(new MyModule());
this.host = HostFactory.New(x =>
{
x.SetServiceName("MyService");
x.SetDisplayName("MyService");
x.SetDescription("MyService");
x.RunAsLocalSystem();
x.StartAutomatically();
x.Service<MyWinService>(s =>
{
s.ConstructUsing(() => kernel.Get<MyWinService>());
s.WhenStarted(w => w.Start());
s.WhenStopped(w => w.Stop());
});
});
this.host.Run(); //code blocks here
}
/// <summary>
/// Dispose the service host
/// </summary> …Run Code Online (Sandbox Code Playgroud) c# integration-testing unit-testing windows-services topshelf
我正在开发一个新的C#3.5应用程序,它需要监视Exchange邮箱并在收到电子邮件时执行某些操作.我知道Microsoft现在建议使用Exchange Web服务在Exchange服务器上执行操作,因此我决定使用它.
我还发现了Exchange Web服务托管API(使用版本1.2.1),这似乎使得调用这些Web服务的任务变得更加容易.
我的问题是,有没有人有使用Managed API创建自动化单元/集成测试的经验?
目前我没有Exchange服务器所以我真的想创建某种模拟(我通常使用Moq)但是Microsoft.Exchange.WebServices.Data.ExchangeService没有实现任何我可以模拟的接口.我的代码全部编码为接口并设计用于依赖注入,但我想不出一个抽象出EWS API依赖的好方法.
我正在向我的WCF服务添加一个自定义端点行为,其类扩展BehaviorExtensionElement为初始化它.在我的web.config,我添加以下内容来注册行为扩展:
<system.serviceModel>
<services>
<service name="Service.MyService">
<endpoint address=""
behaviorConfiguration="endpointBehavior"
binding="basicHttpBinding"
contract="Contracts.IMyService"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="endpointBehavior">
<logBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="logBehavior"
type="MyNamespace.MyBehaviorExtensionElement, MyAssembly, Version=0.0.0.1, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)
这工作绝对正常,但我必须指定程序集的版本才能加载它.如果我将程序集引用更改为MyNamespace.MyBehaviorExtensionElement, MyAssembly不带版本/ culture/token,则服务无法启动并显示错误:
描述:处理为此请求提供服务所需的配置文件时发生错误.请查看下面的具体错误详细信息并相应地修改配置文件.
分析器错误消息:为system.serviceModel/behavior创建配置节处理程序时发生错误:无法将扩展元素"logBehavior"添加到此元素.验证扩展是否已在system.serviceModel/extensions/behaviorExtensions的扩展集合中注册.参数名称:element
作为构建过程的一部分,我的程序集版本的最后部分将经常更改.如何web.config在每次构建版本增加(可能是数百次)时不必使用新版本号更新?
我正在使用Ninject来实例化一些带有构造函数arg的对象,例如:
class MyClass
{
public MyClass(string myArg)
{
this.myArg = myArg;
}
}
Run Code Online (Sandbox Code Playgroud)
我需要这个类的实例数量直到运行时才会知道,但我想要做的是确保myArg结果在不同的单例实例中的每个变体(因此请求相同的值两次返回相同的实例,但不同args返回不同的实例).
有没有人知道一个好的,最好是内置的方式这样做?
我找到了一篇为Ninject的旧版本编写的文章如何确保每个激活参数变化的一个实例,但希望有更新版本的更整洁的解决方案.
编辑
以下是我使用的内容,改编自Akim的答案如下:
private readonly ConcurrentBag<string> scopeParameters = new ConcurrentBag<string>();
internal object ParameterScope(IContext context, string parameterName)
{
var param = context.Parameters.First(p => p.Name.Equals(parameterName));
var paramValue = param.GetValue(context, context.Request.Target) as string;
paramValue = string.Intern(paramValue);
if (paramValue != null && !scopeParameters.Contains(paramValue))
{
scopeParameters.Add(paramValue);
}
return paramValue;
}
public override void Load()
{
Bind<MyClass>()
.ToSelf()
.InScope(c => ParameterScope(c, "myArg"));
Bind<IMyClassFactory>()
.ToFactory();
}
Run Code Online (Sandbox Code Playgroud) 我有一个通用接口ICommandHandler<>,每个接口都有许多实现,用于处理特定的实现ICommand,例如:
public class CreateUserCommand : ICommand { ... }
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand> { ... }
Run Code Online (Sandbox Code Playgroud)
当我给出一个ICommand对象时,我试图将它动态地分配给正确的对象ICommandHandler.目前我Invoke在调度员课程中使用了一种非常直接的反思方法:
public void Dispatch<T>(T command) where T : ICommand
{
Type commandType = command.GetType();
Type handlerType = typeof(ICommandHandler<>).MakeGenericType(commandType);
object handler = IoC.Get(handlerType);
MethodInfo method = handlerType.GetMethod("Handle");
method.Invoke(handler, new object[] { command });
}
Run Code Online (Sandbox Code Playgroud)
这种方法存在两个问题.首先它使用慢反射.其次,如果该方法抛出任何类型的异常,那么它将被包裹在一个中TargetInvocationException,如果我重新抛出它,我将丢失堆栈跟踪.
我通过创建委托和使用来制定调用的方法,DynamicInvoke但是这并没有解决异常的问题(我不确定DynamicInvoke是否真的更好Invoke):
public void Dispatch<T>(T command) where T : ICommand
{
Type …Run Code Online (Sandbox Code Playgroud) 我有以下通用方法将一种类型的输入对象序列化为超类型,如下所示:
public string SerialiseAs<TResult, TInput>(TInput input) where TInput : TResult
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TResult));
MemoryStream stream = new MemoryStream();
ser.WriteObject(stream, input);
stream.Position = 0;
StreamReader reader = new StreamReader(stream);
return reader.ReadToEnd();
}
Run Code Online (Sandbox Code Playgroud)
我必须调用此方法指定两种泛型类型,如下所示:
MySubType x = new MySubType();
string json = SerialiseAs<MySuperType, MySubType>(x);
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么不能TInput在这种情况下推断?是因为TResult实际上并没有用作返回类型吗?以下代码更清晰,但由于缺少输入类型而无法编译:
MySubType x = new MySubType();
string json = SerialiseAs<MySuperType>(x);
Run Code Online (Sandbox Code Playgroud) c# ×6
.net ×2
generics ×2
unit-testing ×2
mocking ×1
ninject ×1
reflection ×1
topshelf ×1
wcf ×1
web-config ×1