* used PrivateActionAttribute to protect child actions

* add Lib solution folder
This commit is contained in:
tmont 2011-02-28 01:03:49 +00:00
parent 602a722277
commit 7be30c7d0f
6 changed files with 266 additions and 115 deletions

Binary file not shown.

View File

@ -11,6 +11,18 @@
<see cref="P:Portoa.Web.Filters.IStatusOverridable.StatusCode"/>
</summary>
</member>
<member name="T:Portoa.Web.Controllers.InjectableFilterActionInvoker">
<summary>
Enables you to dynamically add filters to a ControllerActionInvoker. This class will also
perform injection on all filters that are annotated with NeedsBuildUpAttribute.
</summary>
<remarks> Adapted from http://blog.ploeh.dk/2009/12/01/GlobalErrorHandlingInASPNETMVC.aspx </remarks>
</member>
<member name="M:Portoa.Web.Controllers.InjectableFilterActionInvoker.GetFilters(System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor)">
<summary>
Overridden to add the new filters to the default filters
</summary>
</member>
<member name="T:Portoa.Web.Controllers.IErrorController">
<summary>
Signifies that this controller can handle errors that aren't handled by
@ -32,6 +44,18 @@
Executed when the user is forbidden from seeing the requested page
</summary>
</member>
<member name="T:Portoa.Web.Unity.Lifetime.PerRequestLifetimeManager">
<summary>
<see cref="T:Microsoft.Practices.Unity.LifetimeManager"/> whose lifetime lasts as long as the HTTP request.
The object is stored in <c>HttpContext.Current.Items</c>, keyed by a <see cref="T:System.Guid"/>.
</summary>
</member>
<member name="T:Portoa.Web.Unity.Matching.HasAttribute`1">
<summary>
Matching rule that matches when a method is annotated with an attribute
</summary>
<typeparam name="T">The attribute to match against</typeparam>
</member>
<member name="T:Portoa.Web.Models.ResolveWithContainerModelBinder`1">
<summary>
Model binder that uses an <c>IUnityContainer</c> to resolve the model binder designated by
@ -54,6 +78,11 @@
<member name="M:Portoa.Web.Models.ResolveWithServiceProviderModelBinder`1.#ctor(System.IServiceProvider)">
<param name="serviceProvider">The service provider to use to resolve the model binder</param>
</member>
<member name="T:Portoa.Web.Controllers.ServiceProviderControllerFactory">
<summary>
Controller factory that uses a service provider to resolve controllers
</summary>
</member>
<member name="M:Portoa.Web.Util.TagBuilderExtensions.ToMvcHtmlString(System.Web.Mvc.TagBuilder,System.Web.Mvc.TagRenderMode)">
<summary>
Gets the HTML-safe string representation of the tag. Thanks, Microsoft, for making
@ -91,6 +120,12 @@
<param name="displayText">The text that the button will display</param>
<param name="htmlAttributes">Any additional HTML attributes for the input tag</param>
</member>
<member name="T:Portoa.Web.Unity.NeedsBuildUpAttribute">
<summary>
Indicates that an object needs to be built up by the container
</summary>
<see cref="T:Portoa.Web.Controllers.InjectableFilterActionInvoker"/>
</member>
<member name="T:Portoa.Web.Security.IAuthenticationService">
<summary>
Service for authenticating users
@ -203,6 +238,13 @@
not be null.
</summary>
</member>
<member name="M:Portoa.Web.Util.FilterInfoExtensions.Flatten(System.Web.Mvc.FilterInfo)">
<summary>
Flattens a <c>FilterInfo</c> object into a single <c>IEnumerable</c> containing
the <c>ActionFilter</c>, <c>ExceptionFilter</c>, <c>ResultFilter</c> and
<c>AuthorizationFilter</c> collections
</summary>
</member>
<member name="T:Portoa.Web.Util.NoTempDataProvider">
<summary> This class exists to get rid of the SessionState and TempData error. Just google it. </summary>
</member>
@ -261,6 +303,17 @@
Configures the application to use log4net
</summary>
</member>
<member name="T:Portoa.Web.Unity.Lifetime.ExplicitlyDisposableLifetimeManager`1">
<summary>
<see cref="T:Microsoft.Practices.Unity.LifetimeManager"/> decorator that allows you to explicitly control
how the object disposes (useful for 3rd-party objects that do not implement
<see cref="T:System.IDisposable"/>)
</summary>
</member>
<member name="M:Portoa.Web.Unity.Lifetime.ExplicitlyDisposableLifetimeManager`1.#ctor(Microsoft.Practices.Unity.LifetimeManager,System.Action{`0})">
<param name="lifetimeManager">The <c>LifetimeManager</c> to decorate</param>
<param name="dispose">Action to call when the value is removed to dispose of the object</param>
</member>
<member name="T:Portoa.Web.Session.ISessionStore">
<summary>
Provides an interface for interacting with session data
@ -336,6 +389,21 @@
</summary>
<typeparam name="T">The base class/interface to match against</typeparam>
</member>
<member name="M:Portoa.Web.Util.ControllerContextExtensions.GetFromRequest``1(System.Web.Mvc.ControllerContext,System.String)">
<summary>
Gets a value from the request and casts it to the specified type
</summary>
</member>
<member name="M:Portoa.Web.Util.ControllerContextExtensions.GetFromRequest(System.Web.Mvc.ControllerContext,System.String)">
<summary>
Gets a value from the request
</summary>
</member>
<member name="M:Portoa.Web.Util.ControllerContextExtensions.AddModelError(System.Web.Mvc.ControllerContext,System.String,System.String)">
<summary>
Adds an error to the model state
</summary>
</member>
<member name="T:Portoa.Web.ErrorHandling.ErrorWithUserResultFactory`1">
<summary>
<c cref="T:Portoa.Web.ErrorHandling.IErrorResultFactory">Error result factory</c> that returns a result suitable
@ -359,6 +427,17 @@
Session store that uses the current <c>HttpContext</c>
</summary>
</member>
<member name="T:Portoa.Web.Controllers.IInjectableControllerFactory">
<summary>
<c cref="T:System.Web.Mvc.IControllerFactory">IControllerFactory</c> that provides a mechanism to perform injection
on the controller after it is instantiated
</summary>
</member>
<member name="E:Portoa.Web.Controllers.IInjectableControllerFactory.OnControllerInstantiated">
<summary>
Event that fires after a controller is instantiated
</summary>
</member>
<member name="T:Portoa.Web.Controllers.DefaultErrorController">
<summary>
Controller for handling and displaying errors that aren't handled by application code
@ -367,6 +446,11 @@
<member name="M:Portoa.Web.Controllers.DefaultErrorController.#ctor(Portoa.Web.ErrorHandling.IErrorResultFactory)">
<param name="errorResultFactory">The factory to use to create the action results</param>
</member>
<member name="T:Portoa.Web.Controllers.ContainerControllerFactory">
<summary>
Uses an <c>IUnityContainer</c> to create controllers
</summary>
</member>
<member name="T:Portoa.Web.Unity.UnitOfWorkCallHandler">
<summary>
Call handler that wraps a method call in a unit of work
@ -405,6 +489,18 @@
Gets or sets the currently logged in user, or <c>null</c> if no one is logged in
</summary>
</member>
<member name="T:Portoa.Web.Security.ICurrentUserProvider`1">
<summary>
Provides an interface for identifying the current user
</summary>
<typeparam name="T">The user type</typeparam>
</member>
<member name="P:Portoa.Web.Security.ICurrentUserProvider`1.CurrentUser">
<summary>
Returns the user currently performing actions on the site, or <c>null</c>
if the user cannot be identified
</summary>
</member>
<member name="M:Portoa.Web.Controllers.ControllerExtensions.ValidationErrorsToString(System.Web.Mvc.Controller)">
<summary>
Gets all model state errors as a line feed-delimited string
@ -513,22 +609,6 @@
later.
</summary>
</member>
<member name="T:Portoa.Web.Controllers.ContainerControllerFactory">
<summary>
Uses an <c>IUnityContainer</c> to create controllers
</summary>
</member>
<member name="T:Portoa.Web.Controllers.IInjectableControllerFactory">
<summary>
<c cref="T:System.Web.Mvc.IControllerFactory">IControllerFactory</c> that provides a mechanism to perform injection
on the controller after it is instantiated
</summary>
</member>
<member name="E:Portoa.Web.Controllers.IInjectableControllerFactory.OnControllerInstantiated">
<summary>
Event that fires after a controller is instantiated
</summary>
</member>
<member name="T:Portoa.Web.Unity.Matching.Not`1">
<summary>
Negates a matching rule
@ -564,13 +644,19 @@
Reads the app config and applies the Unity configuration, if applicable
</summary>
</member>
<member name="T:Portoa.Web.Models.PagingMenuModel">
<member name="M:Portoa.Web.Util.HttpRequestBaseExtensions.Get``1(System.Web.HttpRequestBase,System.String)">
<summary>
Model for displaying a paging menu
Gets an object from the request variables, or its default value if
the key does not exist
</summary>
<typeparam name="T">The type to convert the value to</typeparam>
<param name="key">The request key of the object to retrieve</param>
</member>
<member name="M:Portoa.Web.Models.PagingMenuModel.#ctor(Portoa.Web.Models.PagedModel)">
<param name="pagedModel">The model used for displaying the paged data</param>
<member name="T:Portoa.Web.Models.PagedModel`1">
<summary>
Strongly-typed model for displaying data that should be paged
</summary>
<typeparam name="T">The type of data to be paged</typeparam>
</member>
<member name="T:Portoa.Web.Models.PagedModel">
<summary>
@ -627,11 +713,114 @@
Gets or sets filtered record set; <c>Count()</c> should be less than or equal to the <see cref="P:Portoa.Web.Models.PagedModel.PageSize">page size</see>
</summary>
</member>
<member name="T:Portoa.Web.Models.PagedModel`1">
<member name="P:Portoa.Web.Models.PagedModel`1.Records">
<summary>
Strongly-typed model for displaying data that is paged
Gets or sets filtered record set; <c>Count()</c> should be less than or equal to the <see cref="P:Portoa.Web.Models.PagedModel.PageSize">page size</see>
</summary>
</member>
<member name="T:Portoa.Web.Models.PagingMenuModel">
<summary>
Model for displaying a paging menu
</summary>
</member>
<member name="M:Portoa.Web.Models.PagingMenuModel.#ctor(Portoa.Web.Models.PagedModel)">
<param name="pagedModel">The model used for displaying the paged data</param>
</member>
<member name="M:Portoa.Web.Models.PagingMenuModel.GetPage(System.Int32)">
<summary>
Gets the data needed to display a link to a certain page
</summary>
<param name="pageNumber">The number of the page to retrieve</param>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Action">
<summary>
Gets or sets action to navigate to when going to the next or previous page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Controller">
<summary>
Gets or sets the controller to navigate to when going to the next or previous page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Start">
<summary>
Gets the starting point of the current page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.ActualEnd">
<summary>
Gets the actual ending point of the current page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.End">
<summary>
Gets the theoretical ending point of the current page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.TotalPages">
<summary>
Gets the total number of pages in the set
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.CurrentPage">
<summary>
Gets the current page number
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.HasPrevious">
<summary>
Gets whether or not a previous page is possible
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.HasNext">
<summary>
Gets whether or not a next page is possible
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.PageSize">
<summary>
Gets the page size
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.TotalCount">
<summary>
Gets the total number of records
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.ShouldShowMenu">
<summary>
Gets whether or not the menu should be shown
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.CurrentPageIsValid">
<summary>
Gets whether or not the current page is a valid page number for the given data
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Pages">
<summary>
Gets the data needed to display a link to all the pages
</summary>
</member>
<member name="T:Portoa.Web.Models.PagingMenuModel.Page">
<summary>
Represents the data needed to show a link to a page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Page.Start">
<summary>
Gets or sets the starting point of this page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Page.End">
<summary>
Gets or sets the ending point of this page
</summary>
</member>
<member name="P:Portoa.Web.Models.PagingMenuModel.Page.Number">
<summary>
Gets or sets the page number
</summary>
<typeparam name="T">The type of data to be paged</typeparam>
</member>
<member name="T:Portoa.Web.Validation.FileTypeAttribute">
<summary>
@ -667,92 +856,11 @@
</summary>
<see cref="T:Portoa.Web.Filters.OverrideStatusCodeFilter"/>
</member>
<member name="T:Portoa.Web.Unity.Matching.HasAttribute`1">
<member name="T:Portoa.Web.Filters.PrivateActionAttribute">
<summary>
Matching rule that matches when a method is annotated with an attribute
</summary>
<typeparam name="T">The attribute to match against</typeparam>
</member>
<member name="T:Portoa.Web.Unity.Lifetime.PerRequestLifetimeManager">
<summary>
<see cref="T:Microsoft.Practices.Unity.LifetimeManager"/> whose lifetime lasts as long as the HTTP request.
The object is stored in <c>HttpContext.Current.Items</c>, keyed by a <see cref="T:System.Guid"/>.
</summary>
</member>
<member name="T:Portoa.Web.Unity.Lifetime.ExplicitlyDisposableLifetimeManager`1">
<summary>
<see cref="T:Microsoft.Practices.Unity.LifetimeManager"/> decorator that allows you to explicitly control
how the object disposes (useful for 3rd-party objects that do not implement
<see cref="T:System.IDisposable"/>)
</summary>
</member>
<member name="M:Portoa.Web.Unity.Lifetime.ExplicitlyDisposableLifetimeManager`1.#ctor(Microsoft.Practices.Unity.LifetimeManager,System.Action{`0})">
<param name="lifetimeManager">The <c>LifetimeManager</c> to decorate</param>
<param name="dispose">Action to call when the value is removed to dispose of the object</param>
</member>
<member name="M:Portoa.Web.Util.HttpRequestBaseExtensions.Get``1(System.Web.HttpRequestBase,System.String)">
<summary>
Gets an object from the request variables, or its default value if
the key does not exist
</summary>
<typeparam name="T">The type to convert the value to</typeparam>
<param name="key">The request key of the object to retrieve</param>
</member>
<member name="M:Portoa.Web.Util.ControllerContextExtensions.GetFromRequest``1(System.Web.Mvc.ControllerContext,System.String)">
<summary>
Gets a value from the request and casts it to the specified type
</summary>
</member>
<member name="M:Portoa.Web.Util.ControllerContextExtensions.GetFromRequest(System.Web.Mvc.ControllerContext,System.String)">
<summary>
Gets a value from the request
</summary>
</member>
<member name="M:Portoa.Web.Util.ControllerContextExtensions.AddModelError(System.Web.Mvc.ControllerContext,System.String,System.String)">
<summary>
Adds an error to the model state
</summary>
</member>
<member name="T:Portoa.Web.Unity.NeedsBuildUpAttribute">
<summary>
Indicates that an object needs to be built up by the container
</summary>
<see cref="T:Portoa.Web.Controllers.InjectableFilterActionInvoker"/>
</member>
<member name="M:Portoa.Web.Util.FilterInfoExtensions.Flatten(System.Web.Mvc.FilterInfo)">
<summary>
Flattens a <c>FilterInfo</c> object into a single <c>IEnumerable</c> containing
the <c>ActionFilter</c>, <c>ExceptionFilter</c>, <c>ResultFilter</c> and
<c>AuthorizationFilter</c> collections
</summary>
</member>
<member name="T:Portoa.Web.Controllers.InjectableFilterActionInvoker">
<summary>
Enables you to dynamically add filters to a ControllerActionInvoker. This class will also
perform injection on all filters that are annotated with NeedsBuildUpAttribute.
</summary>
<remarks> Adapted from http://blog.ploeh.dk/2009/12/01/GlobalErrorHandlingInASPNETMVC.aspx </remarks>
</member>
<member name="M:Portoa.Web.Controllers.InjectableFilterActionInvoker.GetFilters(System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor)">
<summary>
Overridden to add the new filters to the default filters
</summary>
</member>
<member name="T:Portoa.Web.Controllers.ServiceProviderControllerFactory">
<summary>
Controller factory that uses a service provider to resolve controllers
</summary>
</member>
<member name="T:Portoa.Web.Security.ICurrentUserProvider`1">
<summary>
Provides an interface for identifying the current user
</summary>
<typeparam name="T">The user type</typeparam>
</member>
<member name="P:Portoa.Web.Security.ICurrentUserProvider`1.CurrentUser">
<summary>
Returns the user currently performing actions on the site, or <c>null</c>
if the user cannot be identified
Disallows public access to a controller's action. This is basically a more useful version of
<see cref="T:System.Web.Mvc.ChildActionOnlyAttribute"/>. When the action is accessed publicly, an <see cref="T:System.Web.HttpException"/>
with a 404 status code is raised.
</summary>
</member>
</members>

View File

@ -130,7 +130,7 @@ namespace VideoGameQuotes.Api {
Game = Game.ToDto(),
Created = Created,
Categories = Categories.Select(category => category.ToDto()),
TotalVotes = Votes.Count(),
TotalVotes = UpVotes + DownVotes,
UpVotes = UpVotes,
DownVotes = DownVotes,
Score = Score
@ -188,12 +188,12 @@ namespace VideoGameQuotes.Api {
return years == 1 ? "1 year ago" : years + " years ago";
}
if (timespan.TotalDays >= 50) {
if (timespan.TotalDays >= 31) {
var months = (int)Math.Round(timespan.TotalDays / 30);
return months == 1 ? "1 month ago" : months + " months ago";
}
if (timespan.TotalDays >= 10) {
if (timespan.TotalDays >= 7) {
var weeks = (int)Math.Round(timespan.TotalDays / 7);
return weeks == 1 ? "1 week ago" : weeks + " weeks ago";
}
@ -202,11 +202,11 @@ namespace VideoGameQuotes.Api {
return (int)timespan.TotalDays == 1 ? "1 day ago" : (int)timespan.TotalDays + " days ago";
}
if (timespan.TotalMinutes >= 90) {
if (timespan.TotalMinutes >= 60) {
return (int)timespan.TotalHours == 1 ? "1 hour ago" : (int)timespan.TotalHours + " hours ago";
}
if (timespan.TotalSeconds >= 90) {
if (timespan.TotalSeconds >= 60) {
return (int)timespan.TotalMinutes == 1 ? "1 minute ago" : (int)timespan.TotalMinutes + " minutes ago";
}

View File

@ -6,6 +6,7 @@ using System.Text;
using System.Web.Mvc;
using Portoa.Web;
using Portoa.Web.Controllers;
using Portoa.Web.Filters;
using Portoa.Web.Security;
using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models;
@ -53,7 +54,7 @@ namespace VideoGameQuotes.Web.Controllers {
return Json(this.CreateJsonResponse());
}
[ChildActionOnly]
[PrivateAction]
public ActionResult MainMenu() {
var model = new MainMenuModel { User = userProvider.CurrentUser };
return PartialView("MainMenu", model);

View File

@ -6,6 +6,7 @@ using Portoa.Persistence;
using Portoa.Search;
using Portoa.Validation.DataAnnotations;
using Portoa.Web.Controllers;
using Portoa.Web.Filters;
using Portoa.Web.Models;
using Portoa.Web.Results;
using Portoa.Web.Security;
@ -135,7 +136,7 @@ namespace VideoGameQuotes.Web.Controllers {
return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() });
}
[ChildActionOnly]
[PrivateAction]
public ActionResult QuoteOfTheDay() {
var today = DateTime.UtcNow.DayOfYear;
var quote = quoteService.GetQuoteForDayOfYear(today);

View File

@ -13,6 +13,47 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{C8E910E1-B84
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{236929F9-AE7D-4C78-A3D9-E0ED2EA84609}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{4C702D70-7D2E-410D-A3C6-50598863E102}"
ProjectSection(SolutionItems) = preProject
Lib\Antlr3.Runtime.dll = Lib\Antlr3.Runtime.dll
Lib\Iesi.Collections.dll = Lib\Iesi.Collections.dll
Lib\Iesi.Collections.xml = Lib\Iesi.Collections.xml
Lib\LinFu.DynamicProxy.dll = Lib\LinFu.DynamicProxy.dll
Lib\log4net.dll = Lib\log4net.dll
Lib\log4net.xml = Lib\log4net.xml
Lib\Lucene.Net.dll = Lib\Lucene.Net.dll
Lib\Lucene.Net.xml = Lib\Lucene.Net.xml
Lib\Microsoft.Practices.Unity.Configuration.dll = Lib\Microsoft.Practices.Unity.Configuration.dll
Lib\Microsoft.Practices.Unity.Configuration.xml = Lib\Microsoft.Practices.Unity.Configuration.xml
Lib\Microsoft.Practices.Unity.dll = Lib\Microsoft.Practices.Unity.dll
Lib\Microsoft.Practices.Unity.Interception.Configuration.dll = Lib\Microsoft.Practices.Unity.Interception.Configuration.dll
Lib\Microsoft.Practices.Unity.Interception.Configuration.xml = Lib\Microsoft.Practices.Unity.Interception.Configuration.xml
Lib\Microsoft.Practices.Unity.Interception.dll = Lib\Microsoft.Practices.Unity.Interception.dll
Lib\Microsoft.Practices.Unity.Interception.xml = Lib\Microsoft.Practices.Unity.Interception.xml
Lib\Microsoft.Practices.Unity.xml = Lib\Microsoft.Practices.Unity.xml
Lib\Moq.dll = Lib\Moq.dll
Lib\Moq.xml = Lib\Moq.xml
Lib\MySql.Data.dll = Lib\MySql.Data.dll
Lib\NHibernate.ByteCode.LinFu.dll = Lib\NHibernate.ByteCode.LinFu.dll
Lib\NHibernate.ByteCode.LinFu.xml = Lib\NHibernate.ByteCode.LinFu.xml
Lib\NHibernate.dll = Lib\NHibernate.dll
Lib\NHibernate.xml = Lib\NHibernate.xml
Lib\nunit.framework.dll = Lib\nunit.framework.dll
Lib\nunit.framework.xml = Lib\nunit.framework.xml
Lib\Portoa.dll = Lib\Portoa.dll
Lib\Portoa.Log4Net.dll = Lib\Portoa.Log4Net.dll
Lib\Portoa.Log4Net.xml = Lib\Portoa.Log4Net.xml
Lib\Portoa.Lucene.dll = Lib\Portoa.Lucene.dll
Lib\Portoa.Lucene.xml = Lib\Portoa.Lucene.xml
Lib\Portoa.NHibernate.dll = Lib\Portoa.NHibernate.dll
Lib\Portoa.NHibernate.xml = Lib\Portoa.NHibernate.xml
Lib\Portoa.Web.dll = Lib\Portoa.Web.dll
Lib\Portoa.Web.xml = Lib\Portoa.Web.xml
Lib\Portoa.xml = Lib\Portoa.xml
Lib\Remotion.Data.Linq.dll = Lib\Remotion.Data.Linq.dll
Lib\UnityGenerics.dll = Lib\UnityGenerics.dll
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU