diff --git a/.deployment b/.deployment new file mode 100644 index 00000000..3f3f33f2 --- /dev/null +++ b/.deployment @@ -0,0 +1,2 @@ +[config] +project = Oqtane.Server/Oqtane.Server.csproj diff --git a/Oqtane.Server/Infrastructure/InstallationManager.cs b/Oqtane.Server/Infrastructure/InstallationManager.cs index f9a6f01c..c87665ca 100644 --- a/Oqtane.Server/Infrastructure/InstallationManager.cs +++ b/Oqtane.Server/Infrastructure/InstallationManager.cs @@ -1,13 +1,13 @@ -using System.Reflection; +using System; +using System.Diagnostics; using System.IO; using System.IO.Compression; -using Microsoft.Extensions.Hosting; -using Microsoft.AspNetCore.Hosting; +using System.Reflection; using System.Xml; -using Oqtane.Shared; -using System; -using System.Diagnostics; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Hosting; +using Oqtane.Shared; namespace Oqtane.Infrastructure { @@ -27,7 +27,7 @@ namespace Oqtane.Infrastructure public void InstallPackages(string folders, bool restart) { var webRootPath = _environment.WebRootPath; - + var install = InstallPackages(folders, webRootPath); if (install && restart) @@ -101,6 +101,11 @@ namespace Oqtane.Infrastructure filename = Path.Combine(webRootPath, Utilities.PathCombine(entry.FullName.Replace($"wwwroot{Path.DirectorySeparatorChar}", "").Split(Path.DirectorySeparatorChar))); ExtractFile(entry, filename); break; + case "runtimes": + var destSubFolder = Path.GetDirectoryName(entry.FullName); + filename = Path.Combine(binFolder, destSubFolder, filename); + ExtractFile(entry, filename); + break; } } } @@ -121,9 +126,24 @@ namespace Oqtane.Infrastructure { Directory.CreateDirectory(Path.GetDirectoryName(filename)); } - entry.ExtractToFile(filename, true); + if (FileInUse(filename) == false) + entry.ExtractToFile(filename, true); + } + private static bool FileInUse(string path) + { + try + { + using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate)) + { + var flag = fs.CanWrite; + } + return false; + } + catch (IOException ex) + { + return true; + } } - public void UpgradeFramework() { string folder = Path.Combine(_environment.WebRootPath, "Framework"); @@ -131,7 +151,7 @@ namespace Oqtane.Infrastructure { // get package with highest version and clean up any others string packagename = ""; - foreach(string package in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg")) + foreach (string package in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg")) { if (packagename != "") { diff --git a/README.md b/README.md index 4d5072e9..21a1508e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Oqtane Framework Oqtane is a Modular Application Framework for Blazor +[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json) + ![Oqtane](https://github.com/oqtane/framework/blob/master/oqtane.png?raw=true "Oqtane") Oqtane uses Blazor, an open source and cross-platform web UI framework for building single-page apps using .NET and C# instead of JavaScript. Blazor apps are composed of reusable web UI components implemented using C#, HTML, and CSS. Both client and server code is written in C#, allowing you to share code and libraries. diff --git a/azuredeploy.json b/azuredeploy.json new file mode 100644 index 00000000..4dd651bc --- /dev/null +++ b/azuredeploy.json @@ -0,0 +1,197 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.1", + "parameters": { + "sqlServerName": { + "type": "string", + "metadata": { + "description": "The name of the sql server. It has to be unique." + } + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "The name of the sql databaseName. It has to be unique." + } + }, + "sqlAdministratorLogin": { + "type": "string", + "metadata": { + "description": "The admin user of the SQL Server" + } + }, + "sqlAdministratorLoginPassword": { + "type": "securestring", + "metadata": { + "description": "The password of the admin user of the SQL Server" + } + }, + "BlazorWebsiteName": { + "type": "string", + "metadata": { + "description": "The name of the website. It has to be unique." + } + }, + "BlazorSKU": { + "type": "string", + "allowedValues": [ + "Free", + "Shared", + "Basic", + "Standard" + ], + "defaultValue": "Standard" + }, + "BlazorWorkerSize": { + "type": "string", + "allowedValues": [ + "0", + "1", + "2" + ], + "defaultValue": "0" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources." + } + } + }, + "variables": { + "hostingPlanName": "[concat('Oqtane-hostingplan-', uniqueString(resourceGroup().id))]", + "databaseEdition": "Standard", + "databaseCollation": "SQL_Latin1_General_CP1_CI_AS", + "databaseServiceObjectiveName": "Standard" + }, + "resources": [ + { + "name": "[parameters('sqlServerName')]", + "type": "Microsoft.Sql/servers", + "apiVersion": "2014-04-01", + "location": "[resourceGroup().location]", + "tags": { + "displayName": "SqlServer" + }, + "properties": { + "administratorLogin": "[parameters('sqlAdministratorLogin')]", + "administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]", + "version": "12.0" + }, + "resources": [ + { + "name": "[parameters('databaseName')]", + "type": "databases", + "apiVersion": "2015-01-01", + "location": "[resourceGroup().location]", + "tags": { + "displayName": "Database" + }, + "properties": { + "edition": "[variables('databaseEdition')]", + "collation": "[variables('databaseCollation')]", + "requestedServiceObjectiveName": "[variables('databaseServiceObjectiveName')]" + }, + "dependsOn": [ + "[parameters('sqlServerName')]" + ], + "resources": [ + { + "comments": "Transparent Data Encryption", + "name": "current", + "type": "transparentDataEncryption", + "apiVersion": "2014-04-01-preview", + "properties": { + "status": "Enabled" + }, + "dependsOn": [ + "[parameters('databaseName')]" + ] + } + ] + }, + { + "name": "AllowAllMicrosoftAzureIps", + "type": "firewallrules", + "apiVersion": "2014-04-01", + "location": "[resourceGroup().location]", + "properties": { + "endIpAddress": "0.0.0.0", + "startIpAddress": "0.0.0.0" + }, + "dependsOn": [ + "[parameters('sqlServerName')]" + ] + } + ] + }, + { + "name": "[variables('hostingPlanName')]", + "type": "Microsoft.Web/serverfarms", + "location": "[resourceGroup().location]", + "apiVersion": "2014-06-01", + "dependsOn": [], + "tags": { + "displayName": "Blazor" + }, + "properties": { + "name": "[variables('hostingPlanName')]", + "sku": "[parameters('BlazorSKU')]", + "workerSize": "[parameters('BlazorWorkerSize')]", + "numberOfWorkers": 1 + } + }, + { + "apiVersion": "2018-02-01", + "name": "[parameters('BlazorWebsiteName')]", + "type": "Microsoft.Web/sites", + "location": "[parameters('location')]", + "dependsOn": [ + "[variables('hostingPlanName')]" + ], + "tags": { + "[concat('hidden-related:', resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName')))]": "empty", + "displayName": "Website" + }, + "properties": { + "name": "[parameters('BlazorWebsiteName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "siteConfig": { + "webSocketsEnabled": true + } + }, + "resources": [ + { + "type": "sourcecontrols", + "apiVersion": "2018-02-01", + "name": "web", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]", + "[resourceId('Microsoft.Web/Sites/config', parameters('BlazorWebsiteName'), 'connectionstrings')]" + ], + "properties": { + "RepoUrl": "https://github.com/oqtane/oqtane.framework.git", + "branch": "master", + "IsManualIntegration": true + } + }, + { + "apiVersion": "2018-02-01", + "type": "config", + "name": "connectionstrings", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]" + ], + "properties": { + "DefaultConnection": { + "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', parameters('databaseName'), ';User Id=', parameters('sqlAdministratorLogin'), '@', reference(concat('Microsoft.Sql/servers/', parameters('sqlserverName'))).fullyQualifiedDomainName, ';Password=', parameters('sqlAdministratorLoginPassword'), ';')]", + "type": "SQLAzure" + } + } + } + ] + } + ] +}