Update: Plugin Framework & Update

This commit is contained in:
Gary Sharp
2013-02-19 16:10:27 +11:00
parent 8f769809c2
commit e589c5edb4
14 changed files with 855 additions and 149 deletions
+4 -5
View File
@@ -50,9 +50,9 @@
<Reference Include="Quartz">
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
</Reference>
<Reference Include="RazorGenerator.Mvc, Version=1.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="RazorGenerator.Mvc, Version=1.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\RazorGenerator.Mvc.1.5.0.0\lib\net40\RazorGenerator.Mvc.dll</HintPath>
<HintPath>..\packages\RazorGenerator.Mvc.1.5.4.0\lib\net40\RazorGenerator.Mvc.dll</HintPath>
</Reference>
<Reference Include="SignalR, Version=0.5.1.10822, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -83,9 +83,8 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WebActivator, Version=1.5.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\WebActivator.1.5.3\lib\net40\WebActivator.dll</HintPath>
<Reference Include="WebActivatorEx">
<HintPath>..\packages\WebActivatorEx.2.0.1\lib\net40\WebActivatorEx.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
-1
View File
@@ -17,7 +17,6 @@ namespace Disco.Services.Plugins
public virtual void Install(DiscoDataContext dbContext, ScheduledTaskStatus Status) { return; }
public virtual void Initialize(DiscoDataContext dbContext) { return; }
public virtual void Uninstall(DiscoDataContext dbContext, bool UninstallData, ScheduledTaskStatus Status) { return; }
public virtual void BeforeUpdate(DiscoDataContext dbContext, PluginManifest UpdateManifest, ScheduledTaskStatus Status) { return; }
public virtual void AfterUpdate(DiscoDataContext dbContext, PluginManifest PreviousManifest) { return; }
#endregion
-12
View File
@@ -257,18 +257,6 @@ namespace Disco.Services.Plugins
return true;
}
internal bool BeforePluginUpdate(DiscoDataContext dbContext, PluginManifest UpdateManifest, ScheduledTaskStatus Status)
{
// Initialize Plugin
InitializePluginEnvironment(dbContext);
using (var pluginInstance = this.CreateInstance())
{
pluginInstance.BeforeUpdate(dbContext, UpdateManifest, Status);
}
return true;
}
internal bool AfterPluginUpdate(DiscoDataContext dbContext, PluginManifest PreviousManifest)
{
// Initialize Plugin
+104 -2
View File
@@ -86,6 +86,7 @@ namespace Disco.Services.Plugins
{
string pluginsLocation;
string pluginPackagesLocation;
string pluginsStorageLocation;
PluginLibraryUpdateResponse pluginCatalogue;
List<Tuple<PluginManifest, string, PluginLibraryItem>> UpdatePlugins = new List<Tuple<PluginManifest, string, PluginLibraryItem>>();
@@ -94,11 +95,14 @@ namespace Disco.Services.Plugins
pluginCatalogue = Plugins.LoadCatalogue(dbContext);
pluginsLocation = dbContext.DiscoConfiguration.PluginsLocation;
pluginPackagesLocation = dbContext.DiscoConfiguration.PluginPackagesLocation;
pluginsStorageLocation = dbContext.DiscoConfiguration.PluginStorageLocation;
}
DirectoryInfo pluginDirectoryRoot = new DirectoryInfo(pluginsLocation);
if (pluginDirectoryRoot.Exists)
{
MirgrateV1Plugins(pluginsLocation, pluginsStorageLocation);
foreach (DirectoryInfo pluginDirectory in pluginDirectoryRoot.EnumerateDirectories())
{
string pluginManifestFilename = Path.Combine(pluginDirectory.FullName, "manifest.json");
@@ -131,6 +135,105 @@ namespace Disco.Services.Plugins
}
}
internal static void MirgrateV1Plugins(string pluginsLocation, string pluginsStorageLocation)
{
var migrationPackage = Path.Combine(HttpRuntime.BinDirectory, "Disco1.1-1.2PluginMigration.zip");
if (File.Exists(migrationPackage))
{
// eduSTAR.net
var eduSTARPluginPath = Path.Combine(pluginsLocation, "EduSTARnetCertificateProvider");
if (Directory.Exists(eduSTARPluginPath))
{
var eduSTARPluginAssemblyPath = Path.Combine(eduSTARPluginPath, "EduSTARnetCertificateProvider.dll");
if (File.Exists(eduSTARPluginAssemblyPath))
{
// Delete Old Plugin
Directory.Delete(eduSTARPluginPath, true);
// Add New Plugin
eduSTARPluginPath = Path.Combine(pluginsLocation, "eduSTARnet");
using (var migrationZipPackageStream = new FileStream(migrationPackage, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (ZipArchive migrationZipPackage = new ZipArchive(migrationZipPackageStream))
{
var pluginZipPackage = migrationZipPackage.Entries.Where(e => e.Name.Equals("eduSTARnet.discoPlugin", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
if (pluginZipPackage != null)
{
using (var pluginPackageStream = pluginZipPackage.Open())
{
using (ZipArchive pluginPackageArchive = new ZipArchive(pluginPackageStream))
{
foreach (var entry in pluginPackageArchive.Entries)
{
var entryPath = Path.Combine(eduSTARPluginPath, entry.FullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryPath));
using (var entryOutput = new FileStream(entryPath, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (var entryStream = entry.Open())
{
entryStream.CopyTo(entryOutput);
}
}
}
}
}
}
}
}
}
}
// LWT
var LWTPluginPath = Path.Combine(pluginsLocation, "LWTWarrantyProvider");
if (Directory.Exists(LWTPluginPath))
{
var LWTPluginAssemblyPath = Path.Combine(LWTPluginPath, "LWTWarrantyProvider.dll");
if (File.Exists(LWTPluginAssemblyPath))
{
// Delete Old Plugin
Directory.Delete(LWTPluginPath, true);
// Delete Plugin Storage
var LWTPluginStoragePath = Path.Combine(pluginsStorageLocation, "LWTWarrantyProvider");
if (Directory.Exists(LWTPluginStoragePath))
Directory.Delete(LWTPluginStoragePath, true);
// Add New Plugin
LWTPluginPath = Path.Combine(pluginsLocation, "LWTPlugin");
using (var migrationZipPackageStream = new FileStream(migrationPackage, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (ZipArchive migrationZipPackage = new ZipArchive(migrationZipPackageStream))
{
var pluginZipPackage = migrationZipPackage.Entries.Where(e => e.Name.Equals("LWTPlugin.discoPlugin", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
if (pluginZipPackage != null)
{
using (var pluginPackageStream = pluginZipPackage.Open())
{
using (ZipArchive pluginPackageArchive = new ZipArchive(pluginPackageStream))
{
foreach (var entry in pluginPackageArchive.Entries)
{
var entryPath = Path.Combine(LWTPluginPath, entry.FullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryPath));
using (var entryOutput = new FileStream(entryPath, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (var entryStream = entry.Open())
{
entryStream.CopyTo(entryOutput);
}
}
}
}
}
}
}
}
}
}
}
}
internal static void ExecuteTaskInternal(ScheduledTaskStatus Status, string pluginPackagesLocation, List<Tuple<PluginManifest, string, PluginLibraryItem>> UpdatePlugins)
{
while (UpdatePlugins.Count > 0)
@@ -211,10 +314,9 @@ namespace Disco.Services.Plugins
var updatePluginPath = Path.Combine(dbContext.DiscoConfiguration.PluginsLocation, string.Format("{0}.discoPlugin", updateManifest.Id));
File.Move(packageTempFilePath, updatePluginPath);
if (existingManifest != null && Plugins.PluginsLoaded)
if (existingManifest != null)
{
PluginsLog.LogBeforeUpdate(existingManifest, updateManifest);
existingManifest.BeforePluginUpdate(dbContext, updateManifest, Status);
}
}
}
@@ -17,11 +17,11 @@ namespace Disco.Services.Plugins
{
this.Status.UpdateStatus(0, "Updating plugins after Disco update", "Starting, please wait...");
// Wait for App to Load (6 Seconds)
// Wait for App to Load (10 Seconds)
for (int i = 0; i < 10; i++)
{
this.Status.UpdateStatus(10 * i);
System.Threading.Thread.Sleep(600);
System.Threading.Thread.Sleep(1000);
}
// Update Catalogue
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.0214.1848")]
[assembly: AssemblyFileVersion("1.2.0214.1848")]
[assembly: AssemblyVersion("1.2.0219.1605")]
[assembly: AssemblyFileVersion("1.2.0219.1605")]
+14
View File
@@ -4,6 +4,7 @@ using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using SignalR;
namespace Disco.Web
{
@@ -71,6 +72,19 @@ namespace Disco.Web
public static void RegisterUpdateRoutes(RouteCollection routes)
{
// Task Status SignalR Route
routes.MapConnection<Disco.Services.Tasks.ScheduledTasksLiveStatusService>(
"API_Logging_TaskStatusNotifications",
"API/Logging/TaskStatusNotifications/{*operation}");
// Task Status Ajax Route
routes.MapRoute(
name: "API_Logging_ScheduledTaskStatus", // Route name
url: "API/Logging/ScheduledTaskStatus/{id}", // URL with parameters
defaults: new { area = "API", controller = "Logging", action = "ScheduledTaskStatus", id = UrlParameter.Optional }, // Parameter defaults
namespaces: new string[] { "Disco.Web.Areas.API.Controllers" } // Controllers Namespace Only
);
// Update Route
routes.MapRoute(
name: "Update", // Route name
+7 -2
View File
@@ -21,7 +21,7 @@ namespace Disco.Web.Controllers
{
if (!Request.IsLocal && !InitialConfigController.ServerIsCoreSKU.Value)
{
filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.ServiceUnavailable, "Initial Configuration of Disco is only allowed via a local connection");
filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.ServiceUnavailable, "Initialization Configuration of Disco is only allowed via a local connection");
}
base.OnActionExecuting(filterContext);
}
@@ -30,7 +30,12 @@ namespace Disco.Web.Controllers
{
var status = UpdatePluginsAfterDiscoUpdateTask.UpdateDiscoPlugins(true);
return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId));
var model = new Models.Update.IndexModel()
{
SessionId = status.SessionId
};
return View(model);
}
}
}
+12 -7
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Net;
@@ -43,13 +44,18 @@ namespace Disco.Web
timer_last = timer.ElapsedMilliseconds;
// Check for Post-Update
Version previousVersion;
Version currentVersion = Disco.BI.Interop.Community.UpdateCheck.CurrentDiscoVersion();
using (DiscoDataContext dbContext = new DiscoDataContext())
bool ignoreVersionUpdate = false;
bool.TryParse(ConfigurationManager.AppSettings["DiscoIgnoreVersionUpdate"], out ignoreVersionUpdate);
Version previousVersion = null;
if (!ignoreVersionUpdate)
{
previousVersion = dbContext.DiscoConfiguration.InstalledDatabaseVersion;
using (DiscoDataContext dbContext = new DiscoDataContext())
{
previousVersion = dbContext.DiscoConfiguration.InstalledDatabaseVersion;
}
}
if (currentVersion == previousVersion)
if (ignoreVersionUpdate || Disco.BI.Interop.Community.UpdateCheck.CurrentDiscoVersion() == previousVersion)
{
// Normal Startup
@@ -86,7 +92,6 @@ namespace Disco.Web
else
{
// Post-Update Startup
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterUpdateRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles();
@@ -94,7 +99,7 @@ namespace Disco.Web
using (DiscoDataContext dbContext = new DiscoDataContext())
{
dbContext.DiscoConfiguration.InstalledDatabaseVersion = currentVersion;
dbContext.DiscoConfiguration.InstalledDatabaseVersion = Disco.BI.Interop.Community.UpdateCheck.CurrentDiscoVersion();
dbContext.SaveChanges();
}
}
+12
View File
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Models.Update
{
public class IndexModel
{
public string SessionId { get; set; }
}
}
+261
View File
@@ -0,0 +1,261 @@
@model Disco.Web.Models.Update.IndexModel
@{
ViewBag.Title = "Disco Post-Update Configuration";
Layout = "~/Areas/Public/Views/Shared/_Layout.cshtml";
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/Style/Config");
}
<div style="min-height: 300px;">
<div id="scheduledTaskStatus" class="form" style="width: 520px;" data-bind="visible: Initialized">
<h2 data-bind="text: TaskName">&nbsp;</h2>
<table>
<tr data-bind="visible: IsRunning">
<th class="process" data-bind="text: CurrentProcess">&nbsp;
</th>
</tr>
<tr data-bind="visible: IsRunning">
<td class="description" data-bind="text: CurrentDescription">&nbsp;
</td>
</tr>
<tr data-bind="visible: IsRunning">
<td class="progress">
<div data-bind="progressValue: Progress">
</div>
</td>
</tr>
<tr data-bind="visible: FinishedTimestamp">
<td class="finishedTimestamp">
<h3>Finished: <span data-bind="text: FinishedTimestampFormatted"></span>
</h3>
</td>
</tr>
<tr data-bind="visible: FinishedTimestamp() && !TaskExceptionMessage()">
<td class="finishedMessage" data-bind="css: { finishedRedirect: FinishedUrl }">
<span data-bind="text: FinishedMessage"></span>
</td>
</tr>
<tr data-bind="visible: TaskExceptionMessage">
<td class="exception">Last Error:
<div class="code" data-bind="text: TaskExceptionMessage">
</div>
</td>
</tr>
<tr data-bind="visible: NextScheduledTimestamp">
<td class="nextScheduledTimestamp">Next Scheduled: <span data-bind="text: NextScheduledTimestampFormatted"></span>
</td>
</tr>
</table>
</div>
</div>
<script type="text/javascript">
ko.bindingHandlers.progressValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var $element = $(element);
if (!$element.is('.ui-progressbar'))
$element.progressbar();
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var v = ko.utils.unwrapObservable(valueAccessor());
var vInt = parseInt(v);
if (vInt >= 0) {
$(element).progressbar('option', 'value', vInt);
}
}
};
//* http://webcloud.se/log/JavaScript-and-ISO-8601/
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
return this;
}
</script>
<script type="text/javascript">
$(function () {
var sessionId = '@(Model.SessionId)';
var sessionStatusUrl = '@(Url.Action(MVC.API.Logging.ScheduledTaskStatus(Model.SessionId)))';
// Clear Menu
$('#menu').empty();
var view = $('#scheduledTaskStatus');
var vm = null;
var liveConnection = null;
var statusViewModel = function (sessionId) {
var self = this;
self.Initialized = ko.observable(false);
self.TimestampParse = function (timestamp) {
if (timestamp) {
if (timestamp.indexOf("\/Date(") == 0)
return new Date(parseInt(timestamp.substr(6)));
else
return (new Date()).setISO8601(timestamp);
}
return new Date();
}
self.TimestampFormat = function (timestamp) {
var addZero = function (v) { v = v + ''; if (v.length == 1) v = '0' + v; return v; }
return timestamp.getFullYear() + '/' + addZero((1 + timestamp.getMonth())) + '/' + addZero(timestamp.getDate()) + ' ' + addZero(timestamp.getHours()) + ':' + addZero(timestamp.getMinutes()) + ':' + addZero(timestamp.getSeconds());
}
self.SessionId = sessionId;
self.TaskName = ko.observable(null);
self.StatusVersion = -1;
self.Progress = ko.observable(0);
self.CurrentProcess = ko.observable(null);
self.CurrentDescription = ko.observable(null);
self.IsRunning = ko.observable(null);
self.TaskExceptionMessage = ko.observable(null);
self.FinishedTimestamp = ko.observable(null);
self.NextScheduledTimestamp = ko.observable(null)
self.NextScheduledTimestampFormatted = ko.computed(function () {
return self.TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));
});
self.FinishedTimestampFormatted = ko.computed(function () {
return self.TimestampFormat(self.TimestampParse(self.FinishedTimestamp()));
});
self.FinishedUrl = ko.observable(null);
self.FinishedMessage = ko.observable(null);
self.Finished = function () {
if (self.FinishedTimestamp()) {
if (self.FinishedUrl() && !self.TaskExceptionMessage()) {
if (self.FinishedMessage())
window.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);
else
window.location.href = self.FinishedUrl();
}
}
}
self.Initialize = function (taskStatus) {
self.TaskName(taskStatus.TaskName);
self.FinishedUrl(taskStatus.FinishedUrl);
self.Progress(taskStatus.Progress);
self.CurrentProcess(taskStatus.CurrentProcess);
self.CurrentDescription(taskStatus.CurrentDescription);
self.IsRunning(taskStatus.IsRunning);
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
self.FinishedMessage(taskStatus.FinishedMessage);
self.Initialized(true);
self.Finished();
}
self.Update = function (taskStatus) {
if (!self.Initialized())
return self.Initialize(taskStatus);
if (taskStatus.StatusVersion < self.StatusVersion)
return; // Have Newer Status Update
self.StatusVersion = taskStatus.StatusVersion;
if (taskStatus.ChangedProperties) {
for (var changedPropertyIndex = 0; changedPropertyIndex < taskStatus.ChangedProperties.length; changedPropertyIndex++) {
switch (taskStatus.ChangedProperties[changedPropertyIndex]) {
case 'Progress':
self.Progress(taskStatus.Progress);
break;
case 'CurrentProcess':
self.CurrentProcess(taskStatus.CurrentProcess);
break;
case 'CurrentDescription':
self.CurrentDescription(taskStatus.CurrentDescription);
break;
case 'IsRunning':
self.IsRunning(taskStatus.IsRunning);
break;
case 'TaskException':
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
break;
case 'NextScheduledTimestamp':
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
break;
case 'FinishedUrl':
self.FinishedUrl(taskStatus.FinishedUrl);
break;
case 'FinishedMessage':
self.FinishedMessage(taskStatus.FinishedMessage);
break;
case 'FinishedTimestamp':
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
window.setTimeout(self.Finished, 1);
break;
default:
// Ignore
}
}
}
}
}
vm = new statusViewModel(sessionId);
ko.applyBindings(vm, view[0]);
// Start Live Connection
updateWithLive();
function updateWithAjax(onSuccess) {
$.ajax({
url: sessionStatusUrl,
dataType: 'json',
type: 'POST',
traditional: true,
success: update_Received,
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to load Session: ' + errorThrown);
}
});
}
function updateWithLive() {
liveConnection = $.connection('@(Url.Content("~/API/Logging/TaskStatusNotifications"))');
liveConnection.received(update_Received);
liveConnection.start(function () {
liveConnection.send('/addToGroups:' + sessionId);
updateWithAjax();
});
}
function update_Received(taskStatus) {
vm.Update(taskStatus);
}
});
</script>
+317
View File
@@ -0,0 +1,317 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17929
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Disco.Web.Views.Update
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Web;
using Disco.Web.Extensions;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "1.5.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/Update/Index.cshtml")]
public class Index : System.Web.Mvc.WebViewPage<Disco.Web.Models.Update.IndexModel>
{
public Index()
{
}
public override void Execute()
{
#line 2 "..\..\Views\Update\Index.cshtml"
ViewBag.Title = "Disco Post-Update Configuration";
Layout = "~/Areas/Public/Views/Shared/_Layout.cshtml";
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/Style/Config");
#line default
#line hidden
WriteLiteral("\r\n<div");
WriteLiteral(" style=\"min-height: 300px;\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"scheduledTaskStatus\"");
WriteLiteral(" class=\"form\"");
WriteLiteral(" style=\"width: 520px;\"");
WriteLiteral(" data-bind=\"visible: Initialized\"");
WriteLiteral(">\r\n <h2");
WriteLiteral(" data-bind=\"text: TaskName\"");
WriteLiteral(">&nbsp;</h2>\r\n <table>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <th");
WriteLiteral(" class=\"process\"");
WriteLiteral(" data-bind=\"text: CurrentProcess\"");
WriteLiteral(">&nbsp;\r\n </th>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"description\"");
WriteLiteral(" data-bind=\"text: CurrentDescription\"");
WriteLiteral(">&nbsp;\r\n </td>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"progress\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" data-bind=\"progressValue: Progress\"");
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: FinishedTimestamp\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"finishedTimestamp\"");
WriteLiteral(">\r\n <h3>Finished: <span");
WriteLiteral(" data-bind=\"text: FinishedTimestampFormatted\"");
WriteLiteral("></span>\r\n </h3>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: FinishedTimestamp() && !TaskExceptionMessage()\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"finishedMessage\"");
WriteLiteral(" data-bind=\"css: { finishedRedirect: FinishedUrl }\"");
WriteLiteral(">\r\n <span");
WriteLiteral(" data-bind=\"text: FinishedMessage\"");
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: TaskExceptionMessage\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"exception\"");
WriteLiteral(">Last Error:\r\n <div");
WriteLiteral(" class=\"code\"");
WriteLiteral(" data-bind=\"text: TaskExceptionMessage\"");
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: NextScheduledTimestamp\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"nextScheduledTimestamp\"");
WriteLiteral(">Next Scheduled: <span");
WriteLiteral(" data-bind=\"text: NextScheduledTimestampFormatted\"");
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r" +
"\n</div>\r\n<script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n ko.bindingHandlers.progressValue = {\r\n init: function (element, val" +
"ueAccessor, allBindingsAccessor, viewModel) {\r\n var $element = $(elem" +
"ent);\r\n if (!$element.is(\'.ui-progressbar\'))\r\n $elemen" +
"t.progressbar();\r\n },\r\n update: function (element, valueAccessor, " +
"allBindingsAccessor, viewModel) {\r\n var v = ko.utils.unwrapObservable" +
"(valueAccessor());\r\n var vInt = parseInt(v);\r\n if (vInt >=" +
" 0) {\r\n $(element).progressbar(\'option\', \'value\', vInt);\r\n " +
" }\r\n }\r\n };\r\n //* http://webcloud.se/log/JavaScript-and-ISO-860" +
"1/\r\n Date.prototype.setISO8601 = function (string) {\r\n var regexp = \"(" +
"[0-9]{4})(-([0-9]{2})(-([0-9]{2})\" +\r\n \"(T([0-9]{2}):([0-9]{2})(:([0-9]{2" +
"})(\\.([0-9]+))?)?\" +\r\n \"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?\";\r\n " +
" var d = string.match(new RegExp(regexp));\r\n\r\n var offset = 0;\r\n " +
" var date = new Date(d[1], 0, 1);\r\n\r\n if (d[3]) { date.setMonth(d[3] - 1)" +
"; }\r\n if (d[5]) { date.setDate(d[5]); }\r\n if (d[7]) { date.setHour" +
"s(d[7]); }\r\n if (d[8]) { date.setMinutes(d[8]); }\r\n if (d[10]) { d" +
"ate.setSeconds(d[10]); }\r\n if (d[12]) { date.setMilliseconds(Number(\"0.\" " +
"+ d[12]) * 1000); }\r\n if (d[14]) {\r\n offset = (Number(d[16]) *" +
" 60) + Number(d[17]);\r\n offset *= ((d[15] == \'-\') ? 1 : -1);\r\n " +
" }\r\n\r\n offset -= date.getTimezoneOffset();\r\n time = (Number(date) " +
"+ (offset * 60 * 1000));\r\n this.setTime(Number(time));\r\n return th" +
"is;\r\n }\r\n</script>\r\n<script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n $(function () {\r\n var sessionId = \'");
#line 96 "..\..\Views\Update\Index.cshtml"
Write(Model.SessionId);
#line default
#line hidden
WriteLiteral("\';\r\n var sessionStatusUrl = \'");
#line 97 "..\..\Views\Update\Index.cshtml"
Write(Url.Action(MVC.API.Logging.ScheduledTaskStatus(Model.SessionId)));
#line default
#line hidden
WriteLiteral("\';\r\n\r\n // Clear Menu\r\n $(\'#menu\').empty();\r\n\r\n var view = $(" +
"\'#scheduledTaskStatus\');\r\n var vm = null;\r\n\r\n var liveConnection =" +
" null;\r\n\r\n var statusViewModel = function (sessionId) {\r\n var " +
"self = this;\r\n\r\n self.Initialized = ko.observable(false);\r\n\r\n " +
" self.TimestampParse = function (timestamp) {\r\n if (timestamp)" +
" {\r\n if (timestamp.indexOf(\"\\/Date(\") == 0)\r\n " +
" return new Date(parseInt(timestamp.substr(6)));\r\n els" +
"e\r\n return (new Date()).setISO8601(timestamp);\r\n " +
" }\r\n return new Date();\r\n }\r\n self.Ti" +
"mestampFormat = function (timestamp) {\r\n var addZero = function (" +
"v) { v = v + \'\'; if (v.length == 1) v = \'0\' + v; return v; }\r\n re" +
"turn timestamp.getFullYear() + \'/\' + addZero((1 + timestamp.getMonth())) + \'/\' +" +
" addZero(timestamp.getDate()) + \' \' + addZero(timestamp.getHours()) + \':\' + addZ" +
"ero(timestamp.getMinutes()) + \':\' + addZero(timestamp.getSeconds());\r\n " +
" }\r\n\r\n self.SessionId = sessionId;\r\n self.TaskName = ko.o" +
"bservable(null);\r\n self.StatusVersion = -1;\r\n\r\n self.Progr" +
"ess = ko.observable(0);\r\n self.CurrentProcess = ko.observable(null);\r" +
"\n self.CurrentDescription = ko.observable(null);\r\n\r\n self." +
"IsRunning = ko.observable(null);\r\n\r\n self.TaskExceptionMessage = ko.o" +
"bservable(null);\r\n\r\n self.FinishedTimestamp = ko.observable(null);\r\n " +
" self.NextScheduledTimestamp = ko.observable(null)\r\n\r\n self" +
".NextScheduledTimestampFormatted = ko.computed(function () {\r\n re" +
"turn self.TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));\r\n" +
" });\r\n self.FinishedTimestampFormatted = ko.computed(funct" +
"ion () {\r\n return self.TimestampFormat(self.TimestampParse(self.F" +
"inishedTimestamp()));\r\n });\r\n\r\n self.FinishedUrl = ko.obse" +
"rvable(null);\r\n self.FinishedMessage = ko.observable(null);\r\n\r\n " +
" self.Finished = function () {\r\n if (self.FinishedTimestamp(" +
")) {\r\n if (self.FinishedUrl() && !self.TaskExceptionMessage()" +
") {\r\n if (self.FinishedMessage())\r\n " +
" window.setTimeout(function () { window.location.href = self.FinishedUrl();" +
" }, 3000);\r\n else\r\n window.loc" +
"ation.href = self.FinishedUrl();\r\n }\r\n }\r\n " +
" }\r\n\r\n self.Initialize = function (taskStatus) {\r\n " +
" self.TaskName(taskStatus.TaskName);\r\n self.FinishedUrl(taskSt" +
"atus.FinishedUrl);\r\n\r\n self.Progress(taskStatus.Progress);\r\n " +
" self.CurrentProcess(taskStatus.CurrentProcess);\r\n self" +
".CurrentDescription(taskStatus.CurrentDescription);\r\n\r\n self.IsRu" +
"nning(taskStatus.IsRunning);\r\n\r\n self.TaskExceptionMessage(taskSt" +
"atus.TaskExceptionMessage);\r\n\r\n self.FinishedTimestamp(taskStatus" +
".FinishedTimestamp);\r\n self.NextScheduledTimestamp(taskStatus.Nex" +
"tScheduledTimestamp);\r\n\r\n self.FinishedMessage(taskStatus.Finishe" +
"dMessage);\r\n\r\n self.Initialized(true);\r\n\r\n self.Fi" +
"nished();\r\n }\r\n self.Update = function (taskStatus) {\r\n " +
" if (!self.Initialized())\r\n return self.Initializ" +
"e(taskStatus);\r\n\r\n if (taskStatus.StatusVersion < self.StatusVers" +
"ion)\r\n return; // Have Newer Status Update\r\n s" +
"elf.StatusVersion = taskStatus.StatusVersion;\r\n\r\n if (taskStatus." +
"ChangedProperties) {\r\n for (var changedPropertyIndex = 0; cha" +
"ngedPropertyIndex < taskStatus.ChangedProperties.length; changedPropertyIndex++)" +
" {\r\n switch (taskStatus.ChangedProperties[changedProperty" +
"Index]) {\r\n case \'Progress\':\r\n " +
" self.Progress(taskStatus.Progress);\r\n br" +
"eak;\r\n case \'CurrentProcess\':\r\n " +
" self.CurrentProcess(taskStatus.CurrentProcess);\r\n " +
" break;\r\n case \'CurrentDescription\':\r\n " +
" self.CurrentDescription(taskStatus.CurrentDescription" +
");\r\n break;\r\n case \'Is" +
"Running\':\r\n self.IsRunning(taskStatus.IsRunning);" +
"\r\n break;\r\n case \'Task" +
"Exception\':\r\n self.TaskExceptionMessage(taskStatu" +
"s.TaskExceptionMessage);\r\n break;\r\n " +
" case \'NextScheduledTimestamp\':\r\n se" +
"lf.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);\r\n " +
" break;\r\n case \'FinishedUrl\':\r\n " +
" self.FinishedUrl(taskStatus.FinishedUrl);\r\n " +
" break;\r\n case \'FinishedMessage\':\r\n" +
" self.FinishedMessage(taskStatus.FinishedMessage)" +
";\r\n break;\r\n case \'Fin" +
"ishedTimestamp\':\r\n self.FinishedTimestamp(taskSta" +
"tus.FinishedTimestamp);\r\n window.setTimeout(self." +
"Finished, 1);\r\n break;\r\n " +
" default:\r\n // Ignore\r\n " +
"}\r\n }\r\n }\r\n }\r\n }\r\n\r\n " +
" vm = new statusViewModel(sessionId);\r\n ko.applyBindings(vm, view[0]);\r\n\r" +
"\n // Start Live Connection\r\n updateWithLive();\r\n\r\n function" +
" updateWithAjax(onSuccess) {\r\n $.ajax({\r\n url: session" +
"StatusUrl,\r\n dataType: \'json\',\r\n type: \'POST\',\r\n " +
" traditional: true,\r\n success: update_Received,\r\n " +
" error: function (jqXHR, textStatus, errorThrown) {\r\n " +
" alert(\'Unable to load Session: \' + errorThrown);\r\n }\r\n " +
" });\r\n }\r\n function updateWithLive() {\r\n liveConne" +
"ction = $.connection(\'");
#line 249 "..\..\Views\Update\Index.cshtml"
Write(Url.Content("~/API/Logging/TaskStatusNotifications"));
#line default
#line hidden
WriteLiteral(@"');
liveConnection.received(update_Received);
liveConnection.start(function () {
liveConnection.send('/addToGroups:' + sessionId);
updateWithAjax();
});
}
function update_Received(taskStatus) {
vm.Update(taskStatus);
}
});
</script>
");
}
}
}
#pragma warning restore 1591
+37 -34
View File
@@ -1,35 +1,38 @@
<?xml version="1.0"?>
<!-- For more information on using Web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an atrribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<connectionStrings xdt:Transform="Remove" />
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your Web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
<system.webServer>
<modules xdt:Transform="Remove" />
</system.webServer>
<?xml version="1.0"?>
<!-- For more information on using Web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an atrribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<connectionStrings xdt:Transform="Remove" />
<appSettings>
<add key="DiscoIgnoreVersionUpdate" xdt:Transform="Remove" xdt:Locator="Match(key)" />
</appSettings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your Web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
<system.webServer>
<modules xdt:Transform="Remove" />
</system.webServer>
</configuration>
+83 -82
View File
@@ -1,83 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<connectionStrings>
<add name="DiscoDataContext" connectionString="data source=(local);Initial Catalog=Disco;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Windows" />
<customErrors mode="Off" />
<pages controlRenderingCompatibilityVersion="4.0">
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="Disco.BI.Extensions" />
<add namespace="Disco.Web.Extensions" />
</namespaces>
</pages>
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<!--<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />-->
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0-PluginResources" path="/Plugin/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
</DbProviderFactories>
</system.data>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="DiscoIgnoreVersionUpdate" value="false" />
</appSettings>
<connectionStrings>
<add name="DiscoDataContext" connectionString="data source=(local);Initial Catalog=Disco;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Windows" />
<customErrors mode="Off" />
<pages controlRenderingCompatibilityVersion="4.0">
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="Disco.BI.Extensions" />
<add namespace="Disco.Web.Extensions" />
</namespaces>
</pages>
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<!--<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />-->
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0-PluginResources" path="/Plugin/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
</DbProviderFactories>
</system.data>
</configuration>