We have 3 cleints namely- TestingClient, ITestingClient and ITestingClientExtension. Ideally we would like to assign a variable in our winform. In order to assign the variable we declared
TestingClient client = new TestingClient(new Uri("https://rserver.contoso.com:12800")); We get an error stating delegation handler is protected. How do we establish this connection. Thank you
TestingClient.cs begins with this:
{
/// <summary>
/// The base URI of the service.
/// </summary>
public Uri BaseUri { get; set; }
/// <summary>
/// Gets or sets json serialization settings.
/// </summary>
public JsonSerializerSettings SerializationSettings { get; private set; }
/// <summary>
/// Gets or sets json deserialization settings.
/// </summary>
public JsonSerializerSettings DeserializationSettings { get; private set; }
/// <summary>
/// Subscription credentials which uniquely identify client subscription.
/// </summary>
public ServiceClientCredentials Credentials { get; private set; }
/// <summary>
/// Initializes a new instance of the TestingClient class.
/// </summary>
/// <param name='handlers'>
/// Optional. The delegating handlers to add to the http client pipeline.
/// </param>
protected TestingClient(params DelegatingHandler[] handlers) : base(handlers)
{
this.Initialize();
}
/// <summary>
/// Initializes a new instance of the TestingClient class.
/// </summary>
/// <param name='rootHandler'>
/// Optional. The http client handler used to handle http transport.
/// </param>
/// <param name='handlers'>
/// Optional. The delegating handlers to add to the http client pipeline.
/// </param>
protected TestingClient(HttpClientHandler rootHandler,params DelegatingHandler[]handlers):base(rootHandler,handlers)
{
this.Initialize();
}```
In a nutshell, you should use one of the public constructors rather than your current attempt to use one of the protected ones. Here's a screenshot (with public constructors in yellow) from a recent client I generated for that APIs, in the same way yours was generated ("Add REST Client").
For example, your code will need to look more like
Uri u = new Uri("https://rserver.contoso.com:12800")
ServiceCredential sc = ...create a relevant credential...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fill it in
TestingClient client = new TestingClient(u, sc);
Related
So, just started using NLog. I'm doing a programmatic implementation where I'm trying to setup a class that I can import into any project. The class has two methods: CreateLogger() and GenerateLog(). Here is the class in its entirety:
using System;
using NLog;
using NLog.Config;
using NLog.Targets;
namespace LogEngine
{
/// <summary>
/// Create an instance of NLog for use on a per class level.
/// </summary>
internal sealed class EventLog
{
#region Internal Methods
/// <summary>
/// Generates the NLog.Logger object that will control logging facilities in this program.
/// </summary>
/// <returns>
/// static reference to a <see cref="NLog.Logger" /> object.
/// </returns>
internal static Logger CreateLogger(string baseDir = #"${basedir}\")
{
// Setup log configuration object and new file and screen output targets.
var config = new LoggingConfiguration();
var screenTarget = new ConsoleTarget();
config.AddTarget("screen", screenTarget);
var fileTarget = new FileTarget();
config.AddTarget("file", fileTarget);
screenTarget.Layout = #"${newline}${message}";
var MinScreenOutput = new LoggingRule("*", LogLevel.Fatal, screenTarget);
config.LoggingRules.Add(MinScreenOutput);
// Set the properties for the file output target.
fileTarget.FileName = baseDir + #"${appdomain:format={1\}} logs\${shortdate}.log";
fileTarget.Layout = #"${longdate} ${pad:padcharacter=~:padding=29:inner= ${level:uppercase=true}}"
+ #" ${pad:padcharacter=~:padding=30:inner= Event ID\: ${event-properties:item=EventCode}}"
+ #"${newline}${message} ${when:when=level == 'Error':inner=${newline}Class / Method\:"
+ #"${pad:padding=9:inner=}${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"
+ #"${newline}Exception\:${pad:padding=14:inner=}${exception}}${newline}";
// Define what sort of events to send to the file output target.
var MinOutputDebug = new LoggingRule("*", LogLevel.Debug, fileTarget);
config.LoggingRules.Add(MinOutputDebug);
// Set the configuration for the LogManager
LogManager.Configuration = config;
// Get the working instance of the logger.
return LogManager.GetLogger("LogEngine");
}
/// <summary>
/// Passes one log entry to the destination logger.
/// </summary>
/// <param name="log">
/// The <see cref="NLog.Logger" /> object to write the log entry to.
/// </param>
/// <param name="eventId">
/// Four character unique event ID as <see cref="System.String" />.
/// </param>
/// <param name="level">
/// The <see cref="NLog.LogLevel" /> value.
/// </param>
/// <param name="message">
/// The message to save to the log file as <see cref="System.String" />.
/// </param>
/// <param name="ex">
/// If this is an error log event, pass it as an <see cref="System.Exception" /> object.
/// </param>
internal static void GenerateLog(Logger log, string eventId, LogLevel level, string message, Exception ex = null)
{
// Values used for all events.
LogEventInfo logEvent = new LogEventInfo();
logEvent.Properties["EventCode"] = eventId;
logEvent.Level = level;
logEvent.Message = message;
// If we have an error log, make sure the exception is passed.
if (level.Equals(LogLevel.Error))
logEvent.Exception = ex;
// Actually write the log entry.
log.Log(logEvent);
if (level.Equals(LogLevel.Error) || level.Equals(LogLevel.Fatal))
System.Environment.Exit(Convert.ToInt32(eventId));
}
#endregion Internal Methods
}
}
In the CreateLogger() method, you'll see there is a default parameter. So, how things work is when I call CreateLogger() in my program at the start of my class, I pass no parameters and the ${basedir} value is used to generate initial logging:
internal class Program
{
#region Private Fields
private static Logger log = EventLog.CreateLogger();
#endregion Private Fields
...
However, during execution, I need to change the logging location from ${basedir} to a value that I pull from a SQL database. Here is how I do that:
if (!path.Equals(null))
{
sArgs.path = path.ToString().Trim();
//NLog.Config.SimpleConfigurator.ConfigureForFileLogging(sArgs.path + #"Logs\log1.txt", LogLevel.Debug);
//LogManager.Shutdown();
//LogManager.ReconfigExistingLoggers();
log = EventLog.CreateLogger(sArgs.path);
LogManager.ReconfigExistingLoggers();
}
"path" is an object returned by a call to SQLCommand.ExecuteScalar(). It is the replacement for ${basedir} that I need to connect my Logger to. If the path is not null, then I convert it to a string and store it into a singleton class instantiated as "sArgs". There are some commented out code here to show how I've been trying to resolve this issue.
Okay, so what I'm seeing is in the last code block (when I set "log" to a new instance generated by CreateLogger(sArgs.path)) I can see that my logging path in the log object is actually updating. But, when I get to the first opportunity to log an event, it is still using the old Logger instance (so ${basedir} is still in use, not sArgs.path).
My question is, what am I missing that is keeping the change to "log" that I can plainly see while stepping my code in the debugger from actually becoming the location for the Logger object? Or is it that I'm doing the EventLog class completely wrong?
Thank you for any insights you can provide to this problem.
For each and every class where you use private static Logger log = EventLog.CreateLogger();, you need to change the baseDir whenever you do not want the default baseDir defined in you EventLogclass to be used.
You did not provide the code for your singleton class sArgs, or any other samples of the classes where you want to use your EventLog.
Using your code, I only changed your EventLog to EventLogger and also the default CreateLogger to internal static Logger CreateLogger(string baseDir = #"C:\Temp\NLog\Default\"):
using System;
using NLog;
namespace ConsoleApplication1
{
class Program
{
private static Logger log = EventLogger.CreateLogger();
static void Main(string[] args)
{
EventLogger.GenerateLog(log, "1", LogLevel.Debug, "Default", null);
log = EventLogger.CreateLogger(#"C:\Temp\NLog\New\");
LogManager.ReconfigExistingLoggers();
EventLogger.GenerateLog(log, "2", LogLevel.Debug, "New", null);
Class1.DoSomething();
Console.WriteLine("Press ENTER to exit");
Console.ReadLine();
}
}
}
And Class1:
using NLog;
namespace ConsoleApplication1
{
public static class Class1
{
private static Logger log = EventLogger.CreateLogger();
public static void DoSomething()
{
EventLogger.GenerateLog(log, "3", LogLevel.Debug, "Class1.DoSomething", null);
}
}
}
Running the code result in the following output:
Log EventId 1 will be written to C:\Temp\NLog\Default\ConsoleApplication1.vshost.exe\logs
Log EventId 2 will be written to C:\Temp\NLog\New\ConsoleApplication1.vshost.exe\logs
and LogEventId 3 in Class1.cs will be written to C:\Temp\NLog\Default\ConsoleApplication1.vshost.exe\logs because in Class1.cs when the log was initialised, the default path was used. If you want to change the baseDir of the log in Class1.cs (and subsequent classes) you will need to update the paths individually.
Hope this helps.
Thank you, #Riann for your help and added comments. I actually got this working as a singleton class without affecting the ability of ${callsite} to know the actual method and line where the error is caught. Here is how I did it starting with the updated EventLog class:
using System;
using NLog;
using NLog.Config;
using NLog.Targets;
namespace LogEngine
{
/// <summary>
/// Create an instance of NLog for use on a per class level.
/// </summary>
internal sealed class EventLog
{
#region Constructors
static EventLog()
{
}
private EventLog()
{
this.CreateLogger();
}
#endregion Constructors
#region Singleton Objects
internal static EventLog logger { get { return _logger; } }
private static readonly EventLog _logger = new EventLog();
#endregion Singleton Objects
#region Private Fields
private static Logger _log;
#endregion Private Fields
#region Internal Methods
/// <summary>
/// Generates the NLog.Logger object that will control logging facilities in this program.
/// </summary>
internal void CreateLogger(string baseDir = #"${basedir}\")
{
// Setup log configuration object and new file and screen output targets.
var config = new LoggingConfiguration();
var screenTarget = new ConsoleTarget();
config.AddTarget("screen", screenTarget);
var fileTarget = new FileTarget();
config.AddTarget("file", fileTarget);
screenTarget.Layout = #"${newline}${message}";
var MinScreenOutput = new LoggingRule("*", LogLevel.Fatal, screenTarget);
config.LoggingRules.Add(MinScreenOutput);
// Set the properties for the file output target.
fileTarget.FileName = baseDir + #"${appdomain:format={1\}} logs\${shortdate}.log";
fileTarget.Layout = #"${longdate} ${pad:padcharacter=~:padding=29:inner= ${level:uppercase=true}}"
+ #" ${pad:padcharacter=~:padding=30:inner= Event ID\: ${event-properties:item=EventCode}}"
+ #"${newline}${message} ${when:when=level == 'Error':inner=${newline}Class / Method\:"
+ #"${pad:padding=9:inner=}${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"
+ #"${newline}Exception\:${pad:padding=14:inner=}${exception}}"
+ #"${when:when=level == 'Fatal':inner=${newline}Class / Method\:"
+ #"${pad:padding=9:inner=}${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"
+ #"${newline}Exception\:${pad:padding=14:inner=}${exception}}${newline}";
// Define what sort of events to send to the file output target.
var MinOutputDebug = new LoggingRule("*", LogLevel.Debug, fileTarget);
config.LoggingRules.Add(MinOutputDebug);
// Set the configuration for the LogManager
LogManager.Configuration = config;
// Get the working instance of the logger.
_log = LogManager.GetLogger("LogEngine");
}
/// <summary>
/// Passes one log entry to the destination logger and associated exception information.
/// </summary>
/// <remarks>
/// Use this form of the method when <see cref="NLog.LogLevel.Error" /> or
/// <see cref="NLog.LogLevel.Fatal" /> is used.
/// </remarks>
/// <param name="caller">
/// <see cref="System.String" /> holding information about the calling method.
/// </param>
/// <param name="eventId">
/// Four character unique event ID as <see cref="System.String" />.
/// </param>
/// <param name="level">
/// The <see cref="NLog.LogLevel" /> value.
/// </param>
/// <param name="message">
/// The message to save to the log file as <see cref="System.String" />.
/// </param>
/// <param name="ex">
/// If this is an error log event, pass it as an <see cref="System.Exception" /> object.
/// </param>
internal void GenerateLog(string eventId, LogLevel level, string message, Exception ex)
{
// Values used for all events.
LogEventInfo logEvent = new LogEventInfo();
logEvent.Properties["EventCode"] = eventId;
logEvent.Level = level;
logEvent.Message = message;
logEvent.Exception = ex;
// Actually write the log entry.
_log.Log(logEvent);
if (level.Equals(LogLevel.Error) || level.Equals(LogLevel.Fatal))
Environment.Exit(Convert.ToInt32(eventId));
}
/// <summary>
/// Passes one log entry to the destination logger.
/// </summary>
/// <remarks>
/// Use this form of the method when <see cref="NLog.LogLevel.Warn" /> or
/// <see cref="NLog.LogLevel.Info" /> is used.
/// </remarks>
/// <param name="caller">
/// <see cref="System.String" /> holding information about the calling method.
/// </param>
/// <param name="eventId">
/// Four character unique event ID as <see cref="System.String" />.
/// </param>
/// <param name="level">
/// The <see cref="NLog.LogLevel" /> value.
/// </param>
/// <param name="message">
/// The message to save to the log file as <see cref="System.String" />.
/// </param>
internal void GenerateLog(string eventId, LogLevel level, string message)
{
// Values used for all events.
LogEventInfo logEvent = new LogEventInfo();
logEvent.Properties["EventCode"] = eventId;
logEvent.Level = level;
logEvent.Message = message;
// Actually write the log entry.
_log.Log(logEvent);
}
#endregion Internal Methods
}
}
Basically, aside from the Contructor, Singleton Objects, and Private Fields regions, all of which is new, I had to change my calls in CreateLogger() and GenerateLog() to affect the private field _log. I did also make GenerateLogger() an overloaded method, but that doesn't affect overall usage of the EventLog class.
In each of my other classes, I only had to change how I open my logger. I was going to do this at the method level, but decided to do it at class level:
internal class Program
{
#region Private Fields
private static readonly EventLog log = EventLog.logger;
#endregion Private Fields
...
So, for any method I'm in, if I want to change my logging path, I just ask my log instance to call CreateLogger(path):
if (!path.Equals(null))
{
sArgs.path = path.ToString().Trim();
log.CreateLogger(sArgs.path);
}
Any future calls, no matter what class I'm in, I just need to call GenerateLog() and I'll have the right log path.
In my Web api project I am having a controller DocumentViewerV1Controller which has a code as:
/// <summary>
///
/// </summary>
/// <param name="documentViewerService"></param>
public DocumentViewerV1Controller(IDocumentViewerService<HtmlViewInformation> documentViewerService)
{
_documentViewerHtmlService = documentViewerService;
}
/// <summary>
///
/// </summary>
/// <param name="documentViewerService"></param>
public DocumentViewerV1Controller(IDocumentViewerService<PageImage> documentViewerService)
{
_documentViewerImageService = documentViewerService;
}/// <summary>
/// Rendering Document as Html
/// </summary>
/// <returns></returns>
[HttpGet]
[Route(WebApiConfig.RootApiUri + "/v1/viewashtml/{docid}")]
public string ViewAsHtml(string docId)
{
var documentInfo = new DocumentInfo { DocumentName = HostingEnvironment.MapPath("~/Uploads/") + docId };
var response = _documentViewerHtmlService.RenderDocument(documentInfo, DocumentRenderType.Html);
return GenerateResponse(response);
}
When I run my service, make a call and debug the constructor initialization, It doesn't goes through the initialization which makes _documentViewerHtmlService as null, eventually fails returning Null reference Exception.
Is it possible to have service Interface as IDocumentViewerService?
Yes, but you'll need to remove one of the constructors or tell it which one to use.
container.RegisterType<IViewerInformation, HtmlViewerInformation>();
container.RegisterType<IDocumentViewerService<IViewerInformation>, DocumentViewerServce<IViewerInformation>>();
You may / may not also need to initialize some of the constructors which you can do by
container.RegisterType<IDocumentViewerService<IViewerInformation>, DocumentViewerServce<IViewerInformation>>(
new InjectionConstructor(...));
Short:
For each and every request a new OWIN context is created, I would like to be able to prevent this for certain resource types or paths (images, css, js).
Full:
In our application start-up we register a dbcontext creation delegate so that the dbcontext will be created just once per request.
public virtual void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(Factory.DbContextCreateDelegate);
}
If a client makes a request for the style sheet, an OWIN context will be created an thus a new dbcontext will also be created. I would like to be able to either not create the OwinContext at all, or at least to be able to prevent some of it's "on create" callbacks to be executed for certain request types/paths.
Alternatively, as I can see why the approach of (partially) "disabling" OWIN would lead to problems, I would like to hear what the best practice would be? How can I serve a static file without creating a database context for each request? (small remark here is that our static files are embedded resources served using a virtual path provider... The problem also occurs for "normal" static files.)
Background: Yesterday I started noticing that every now and then some parts of our application did not load. Sometimes it was single image, sometimes the entire CSS file. After some investigation I saw that some requests were throwing http 500 errors, the exception thrown was often things like a SQL connection time out (but also other exceptions).
While we are of course trying to fix those exceptions. I do believe it to be complete nonsense for our application to set up a database connection when a client makes a request for a single image... That's about 10 database connections for a single page request???
Seems to me like such an obvious problem but I have been Googling all of yesterday and found nothing close to a solution or work around. What am I missing stack?
EDIT: I just tried an approach where I did not actually create the dbcontext but a stub instead. In hindsight this obviously is not the solution to this problem as the OwinContext tries to continue it's process and will critically fail when it tries to get the user from the database using that stub dbcontext. The dbcontext is not the problem, I need to completely bypass Owin... I think...
Microsoft.Owin.StaticFiles to the rescue!
I would still like to know why this is not enabled by default in the MVC OWIN template application. But for most cases it is just a matter of a single line of code to enable static files in OWIN.
BASIC SCENARIO
Setting up Owin to treat a folder and its contents as static files:
public virtual void Configuration(IAppBuilder app)
{
app.UseStaticFiles("/PathToYourStaticFilesFolder");
}
SCENARIO WITH EMBEDDED RESOURCES
Unfortunately for me we are serving most of our static content as embedded resources using an implementation of a VirtualPathProvider. Luckily this is also relatively easy to implement, though it does require writing a wrapper around your VirtualPathProvider to implement the required IFileSystem and IFileInfo interfaces that OWIN requires.
Relevant parts of code from my final solution, not posting the entire VirtualPathProvider as there are plenty of examples for that online.
The wrapper around the VirtualPathProvider:
/// <summary>
/// Represents a virtual file system.
/// A wrapper around <see cref="MyCustomVirtualPathProvider"/> implementing
/// IFileSystem for use in Owin StaticFiles.
/// </summary>
public class VirtualFileSystem : IFileSystem
{
/// <summary>
/// Locate the path in the virtual path provider
/// </summary>
/// <param name="subpath">The path that identifies the file</param>
/// <param name="fileInfo">The discovered file if any</param>
/// <returns>
/// True if a file was located at the given path
/// </returns>
public bool TryGetFileInfo(string subpath, out IFileInfo fileInfo)
{
MyCustomVirtualPathProvider virtualPathProvider =
(MyCustomVirtualPathProvider) HostingEnvironment.VirtualPathProvider;
if (!virtualPathProvider.FileExists(subpath))
{
fileInfo = null;
return false;
}
try
{
EmbeddedResourceVirtualFile virtualFile =
(EmbeddedResourceVirtualFile) virtualPathProvider.GetFile(subpath);
fileInfo = new EmbeddedResourceFileInfo(virtualFile);
return true;
}
catch (InvalidCastException)
{
fileInfo = null;
return false;
}
}
/// <summary>
/// Not used in our implementation
/// </summary>
/// <param name="subpath"></param>
/// <param name="contents"></param>
/// <returns></returns>
public bool TryGetDirectoryContents(string subpath, out IEnumerable<IFileInfo> contents)
{
throw new NotImplementedException();
}
}
The wrapper around the embedded resource:
/// <summary>
/// Represents the file info of an embedded resource
/// </summary>
public class EmbeddedResourceFileInfo : IFileInfo
{
/// <summary>
/// Return file contents as readonly stream. Caller should dispose stream when complete.
/// </summary>
/// <returns>
/// The file stream
/// </returns>
public Stream CreateReadStream()
{
return virtualFile.Open();
}
/// <summary>
/// The length of the file in bytes, or -1 for a directory info
/// </summary>
public long Length => virtualFile.Length;
/// <summary>
/// The name of the file
/// </summary>
public string Name => virtualFile.Name;
/// <summary>
/// When the file was last modified
/// </summary>
public DateTime LastModified => virtualFile.LastModified;
/// <summary>
/// Returns null as these are virtual files
/// </summary>
public string PhysicalPath => null;
/// <summary>
/// True for the case TryGetDirectoryContents has enumerated a sub-directory
/// </summary>
public bool IsDirectory => virtualFile.IsDirectory;
private readonly EmbeddedResourceVirtualFile virtualFile;
/// <summary>
/// Construct using a <see cref="EmbeddedResourceVirtualFile"/>
/// </summary>
/// <param name="virtualFile"></param>
public EmbeddedResourceFileInfo(EmbeddedResourceVirtualFile virtualFile)
{
this.virtualFile = virtualFile;
}
}
And lastly, setting up Owin to use our virtual file system:
public virtual void Configuration(IAppBuilder app)
{
var staticFilesOptions = new StaticFileOptions
{
FileSystem = new VirtualFileSystem()
};
app.UseStaticFiles(staticFilesOptions);
}
I have the following interface that provides me a way to work with cookies:
/// <summary>
/// Provides an interface that makes it easy to work with cookies.
/// </summary>
public interface ICookies
{
#region Properties
/// <summary>
/// Gets or sets the value of the <see cref="ICookies"/>.
/// </summary>
/// <param name="name">The name of the cookie.</param>
/// <returns>A string that represents the value in this cookie.</returns>
string this[string name] { get; set; }
#endregion
#region Methods
/// <summary>
/// Writes a new cookie.
/// </summary>
/// <param name="name">The name of the cookie.</param>
/// <param name="expiration">The <see cref="DateTime"/> when this cookie expires.</param>
/// <param name="value">The value that the cookie should have.</param>
void Create(string name, string value, DateTime expiration);
/// <summary>
/// Checks wether a cookie with a specific name does exist.
/// </summary>
/// <param name="name">The name of the cookie.</param>
/// <returns><see langword="true"/> if the cookie does exists, otherwise, <see langword="false"/>.</returns>
bool DoesExist(string name);
#endregion
}
And I have the following manager that takes the ICookie interface from above to create cookies. And that class looks like the following:
/// <summary>
/// Provides an easy way to work with cookies on the server.
/// </summary>
public static class CookieManager
{
#region Methods
/// <summary>
/// Writes a new cookie on the.
/// </summary>
/// <param name="cookies">The <see cref="ICookies" /> that is responsible for working with cookies.</param>
/// <param name="name">The name of the cookie.</param>
/// <param name="value">The value of the cookie.</param>
public static void Write(ICookies cookies, string name, string value)
{
if (!Exists(cookies, name))
{
cookies.Create(name, value, DateTime.Now.AddYears(1));
}
cookies[name] = value;
}
/// <summary>
/// Reads a cookie.
/// </summary>
/// <param name="cookies">The <see cref="ICookies" /> that is responsible for working with cookies.</param>
/// <param name="name">The name of the cookie to read.</param>
/// <returns>The value of the cookie.</returns>
/// <exception cref="KeyNotFoundException">The cookie is not existing.</exception>
public static string Read(ICookies cookies, string name)
{
return cookies[name];
}
/// <summary>
/// Check if a cookie does exists.
/// </summary>
/// <param name="cookies">The <see cref="ICookies" /> that is responsible for working with cookies.</param>
/// <param name="name">The name of the cookie.</param>
/// <returns><see langword="true" /> when the cookie does exists, otherwise <see langword="false" />.</returns>
public static bool Exists(ICookies cookies, string name)
{
return cookies.DoesExist(name);
}
#endregion
}
Now, I would like to write a Unit test that mocks the cookie interface to make sure it passes.
I would like to check the following:
When I call CookieManager.Write a cookie should be written and I should be able to read it using the CookieManager.Read function. What's the correct approach for that because I've already tried everything (working with the Verifyable, Setup, SetupGet, SetupSet).
Quite important to say is that I'm working with Moq.
Here's what I have for the moment:
I have a constant first:
protected const string CookieReturnValue = "ReturnValue";
Then I have my mock of ICookie:
protected override void Arrange()
{
cookies = new Mock<ICookies>();
cookies.Setup(c => c.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>()));
cookies.SetupGet(c => c[It.IsAny<string>()]).Returns(CookieReturnValue).Verifiable();
}
Then the test is executed:
protected override void Act()
{
CookieManager.Write(cookies.Object, "MyCookie", "MyValue");
CookieManager.Read(cookies.Object, "MyCookie");
}
And at the very end, the test is verified:
cookies.Verify();
Now, this test is passing, but I'm not too sure if this is the correct way of testing since in my mock, I'm returning the constant 'CookieReturnValue'. I should be able to set it to the value entered as the second parameter in the 'cookies.Setup()' method, where the 2nd parameter holds the value of the cookie.
The main problem here is that the test is also passing if I'm not writing a cookie. I need to make sure that the test is only passing when I'm writing a cookie and then reading the same cookie again.
Can someone if this is the correct way of testing or where that I should adapt it in order to make sure it's working correctly?
You have actually three tests.
The first one tests if the CookieManager checks if a cookie exists, and when not, call Create, then set the cookie:
var cookies = new Mock<ICookies>();
// there's no cookie
cookies.Setup(c => c.DoesExist(It.IsAny<string>())).Returns(false);
CookieManager.Write(cookies.Object, "MyCookie", "MyValue");
// check if create was called with the right parameters
cookies.Verify(c => c.Create("MyCookie", "MyValue", It.IsAny<DateTime>()));
// check if the cookie was set
cookies.VerifySet(mock => mock["MyCookie"] = "MyValue");
The second one tests if the CookieManager checks if a cookie exists, and when it does, don't call Create, then set the cookie:
// there's a cookie
cookies.Setup(c => c.DoesExist(It.IsAny<string>())).Returns(true);
CookieManager.Write(cookies.Object, "MyCookie", "MyValue");
// check if create was NOT called
cookies.Verify(c => c.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>()), Times.Never);
// check if the cookie was set
cookies.VerifySet(mock => mock["MyCookie"] = "MyValue");
The third one tests if the CookieManager attempts to read the cookie:
var cookies = new Mock<ICookies>();
CookieManager.Read(cookies.Object, "MyCookie");
// check if the indexer was used with the right key
cookies.Verify(c => c["MyCookie"]);
Note: simply calling cookies.Verify() does nothing on its own. You either have to provide a delegate to Verify, like I did in my examples, or call VerifyAll to verify all SetUps.
Also, you could make these tests more strict by e.g. using Times.Once or MockBehavior.Strict.
For example, the first test could also be written as:
var cookies = new Mock<ICookies>(MockBehavior.Strict);
// there's no cookie
cookies.Setup(c => c.DoesExist("MyCookie")).Returns(false);
// so one has to be created with the right parameters
cookies.Setup(c => c.Create("MyCookie", "MyValue", It.IsAny<DateTime>()));
cookies.SetupSet(mock => mock["MyCookie"] = "MyValue");
CookieManager.Write(cookies.Object, "MyCookie", "MyValue");
cookies.VerifyAll();
Also, I don't know why the CookieManager sets the cookie value again after it just created it with cookies.Create(...).
Furthermore, there's no need to setup the mock to return the constant CookieReturnValue and then check if that constant is actually returnd my that mock. This would not test the CookieManager, but rather the mock object itself, which is pointless.
I've run into a bit of an issue trying to unit test an MVC site I have: I require a lot of the ASP.NET environment to be running (generation of httpcontexts, sessions, cookies, memberships, etc.) to fully test everything.
Even to test some of the less front end stuff needs memberships in order to properly work, and it's been finicky to get this all spoofed by hand.
Is there a way to spin up an application pool inside of NUnit tests? That seems like the easiest way.
If written properly, you shouldn't need to have a real context, real session, cookies, etc. The MVC framework by default provides a HttpContext that can be mocked/stubbed. I'd recommend using a mocking framework like Moq or Rhino Mocks and creating a MockHttpContext class that creates a mock context with all of the properties that you need to test against set up. Here's a mock HttpContext that uses Moq
/// <summary>
/// Mocks an entire HttpContext for use in unit tests
/// </summary>
public class MockHttpContextBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
public MockHttpContextBase() : this(new Mock<Controller>().Object, "~/")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
/// <param name="controller">The controller.</param>
public MockHttpContextBase(Controller controller) : this(controller, "~/")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
/// <param name="url">The URL.</param>
public MockHttpContextBase(string url) : this(new Mock<Controller>().Object, url)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
/// <param name="controller">The controller.</param>
/// <param name="url">The URL.</param>
public MockHttpContextBase(ControllerBase controller, string url)
{
HttpContext = new Mock<HttpContextBase>();
Request = new Mock<HttpRequestBase>();
Response = new Mock<HttpResponseBase>();
Output = new StringBuilder();
HttpContext.Setup(x => x.Request).Returns(Request.Object);
HttpContext.Setup(x => x.Response).Returns(Response.Object);
HttpContext.Setup(x => x.Session).Returns(new FakeSessionState());
Request.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
Request.Setup(x => x.QueryString).Returns(new NameValueCollection());
Request.Setup(x => x.Form).Returns(new NameValueCollection());
Request.Setup(x => x.ApplicationPath).Returns("~/");
Request.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns(url);
Request.Setup(x => x.PathInfo).Returns(string.Empty);
Response.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
Response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string path) => path);
Response.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(s => Output.Append(s));
var requestContext = new RequestContext(HttpContext.Object, new RouteData());
controller.ControllerContext = new ControllerContext(requestContext, controller);
}
/// <summary>
/// Gets the HTTP context.
/// </summary>
/// <value>The HTTP context.</value>
public Mock<HttpContextBase> HttpContext { get; private set; }
/// <summary>
/// Gets the request.
/// </summary>
/// <value>The request.</value>
public Mock<HttpRequestBase> Request { get; private set; }
/// <summary>
/// Gets the response.
/// </summary>
/// <value>The response.</value>
public Mock<HttpResponseBase> Response { get; private set; }
/// <summary>
/// Gets the output.
/// </summary>
/// <value>The output.</value>
public StringBuilder Output { get; private set; }
}
/// <summary>
/// Provides Fake Session for use in unit tests
/// </summary>
public class FakeSessionState : HttpSessionStateBase
{
/// <summary>
/// backing field for the items in session
/// </summary>
private readonly Dictionary<string, object> _items = new Dictionary<string, object>();
/// <summary>
/// Gets or sets the <see cref="System.Object"/> with the specified name.
/// </summary>
/// <param name="name">the key</param>
/// <returns>the value in session</returns>
public override object this[string name]
{
get
{
return _items.ContainsKey(name) ? _items[name] : null;
}
set
{
_items[name] = value;
}
}
}
There's a few things that you could add further like a HTTP Headers collection, but hopefully it demonstrates what you can do.
To use
var controllerToTest = new HomeController();
var context = new MockHttpContextBase(controllerToTest);
// do stuff that you want to test e.g. something goes into session
Assert.IsTrue(context.HttpContext.Session.Count > 0);
With regards to Membership providers or other providers, you've hit on something that can be hard to test. I would abstract the usage of the provider behind an interface such that you can provide a fake for the interface when testing a component that relies on it. You'll still have trouble unit testing the concrete implementation of the interface that uses the provider however but your mileage may vary as to how far you want/have to go with regards to unit testing and code coverage.
I'm not aware of a way to do that since your code isn't in that process and requires a host that isn't in aspnet either. (I've been wrong before though haha)
Theres an older HttpSimulator from Phil Haack, have you given that a whirl?
http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx
You need to build wrapper interfaces for those services. The original MVC2 and MV3 starter project templates did this by default, but for some reason they dropped that in the latest versions.
You can try to find samples of the original AccountController code to give you a starting place. They used IMembershipService and IFormsAuthenticationService
It's relatively straightforward to mock session, context, etc..
Take a look at the MVCContrib project (http://mvccontrib.codeplex.com/) as they have a helper for creating controllers that have all the various contextual objects populated (like HttpContext).