use msdeploy to install a zip-package on a remote computer from commandline - msdeploy

I have a .zip package that I want to install on a development server from my development machine. So I use the msdeploy to do this automatic for me.
msdeploy.exe -verb:sync -source:package=Debug_Services_14.02.20.1413.zip -dest:auto,computername=DEVELOPMENTSERVER,username=ADMIN_USER,password=ADMIN_PWD
But it fails saying that the ERROR_SITE_DOESNT_EXIST.
Info: Adding sitemanifest (sitemanifest).
Info: Adding createApp (MY_SERVICE).
Info: Adding contentPath (MY_SERVICE).
Error Code: ERROR_SITE_DOES_NOT_EXIST
More Information: Site MY_SERVICE does not exist. Learn more at: http
://go.microsoft.com/fwlink/?LinkId=221672#ERROR_SITE_DOES_NOT_EXIST.
Error count: 1.
But I am trying to install it for the first time! What have I missed?

For example. msdeploy api c#.
Execute MSDeploy from C# program code like an API
public static void AppSynchronization(DeploymentBaseOptions depBaseOptions, string appPath)
{
var deploymentObjectSyncApp = DeploymentManager.CreateObject(
DeploymentWellKnownProvider.Package,
appPath, new DeploymentBaseOptions());
deploymentObjectSyncApp.SyncTo(DeploymentWellKnownProvider.Auto, string.Empty,
depBaseOptions, new DeploymentSyncOptions());
}
where
var deployBaseOptions = new DeploymentBaseOptions
{
ComputerName = #"https://WIN-CCDDFDFDFD:8172/msdeploy.axd",
UserName = #"WIN-CCDDFDFDFD\Al",
Password = "1212121",
AuthenticationType = "Basic"
};
appPath = "C:\mySite.zip";

Related

EFCore SQLite connection string with relative path in asp.net

I have just added SQLite to my asp.net webApi project, and am having trouble working out how get the path to the App_Data folder to pass to DbContextOptionsBuilderUseSqlite
I have the following in the web.config I have a link to an external a config file with the conenction string...
<connectionStrings configSource="config\connectionStrings.config"/>
and in there I have...
<connectionStrings>
<add name="MyDatastore"
connectionString="DataSource=./App_Data/test.sqlite" />
</connectionStrings>
And in my DbContext.OnConfiguring I Have....
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
string path = WebConfigurationManager.ConnectionStrings["MyDatastore"].ConnectionString;
optionsBuilder.UseSqlite(path);
}
}
The path is correctly retrieved (I can see I get the path as configured on connectionStrings.config
so ./App_Data/test.sqlite is passed to optionsBuilder.UseSqlite(path).
However, I get the following error...
SQLite Error 14: 'unable to open database file'.
If I use just connectionString="DataSource=test.sqlite" /> then it seems to magically find the file in the App_Data folder, when I ran on my dev machine in debug, but I had problems on another machine (release build). I assume it is the path, though all I get back is 'unable to open database file'.
I also tried..
connectionString="DataSource=|DataDirectory|test.sqlite" />
This gives me a Illegal characters in path error.
The following does work (full path)
connectionString="d:\0\test.sqlite" />
But I want to be able to use relative paths, eg maybe even .\datastore\test.sqlite.
Does any one have any ideas on this?
Thanks in advance
You'll have to fix up the relative paths at runtime:
var builder = new SqliteConnectionStringBuilder(connectionString);
builder.DataSource = Path.GetFullPath(
Path.Combine(
AppDomain.CurrentDomain.GetData("DataDirectory") as string
?? AppDomain.CurrentDomain.BaseDirectory,
builder.DataSource);
connectionString = builder.ToString();
Works perfectly for me.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dataSource = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "siteDB.db");
optionsBuilder
.UseSqlite($"Data Source={dataSource};");
}
Note: This solution was tested for .Net Core 5, and one can presume it will work on 2.x, 3.x, 5
If you want to use a diferent project than the one provided when you started, you have to specify the correct path ("Data Source = ..\\MyApplication.DAL\\sqliteDatabase.db") in the appsettings.json.
In this presented case, you don't even need to write the method OnConfiguring(DbContextOptionsBuilder optionsBuilder) in the ApplicationDbContext.cs.
You have a full setup bellow (Startup & appsettings.json).
My project structure:
-> MyApplication (solution)
-> MyApplication.UI (initial project of the solution)
-> MyApplication.BL (project)
-> MyApplication.DAL (project)
Inside Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//... other services
services.AddDbContext<ApplicationDbContext>
(x => x.UseSqlite(Configuration.GetConnectionString("SqliteConnection")));
//.... other services and logic
}
In appsettings.json :
"ConnectionStrings": {
"SqliteConnection": "Data Source = ..\\MyApplication.DAL\\sqliteDatabase.db"
}
Works for me on linux, .net core 5.
var builder = new SqliteConnectionStringBuilder("Data Source=MyDatabase.db");
builder.DataSource = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, builder.DataSource);
services.AddDbContext<MyContext>(o => o.UseSqlite(builder.ToString());
Assumes database is in the bin directory, e.g. MyProject/bin/Debug/MyDatabase.db or MyProject/bin/Release/MyDatabase.db.
If you are a .Net Core backend developer who use sqlite, make sure to use below code example. Otherwise SQLite Error 14: 'unable to open database file' error will come.
Startup.cs
var baseDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
string dbPathSystemLog = Path.Combine(baseDirectory, "CAMSCoreSystemLog.db");
SystemLogDBContext.cs
public class SystemLogDBContext : DbContext
{
public SystemLogDBContext(DbContextOptions<SystemLogDBContext> options) : base(options)
{
Database.EnsureCreated();
}
}
This line will create the Db if not exist
Database.EnsureCreated();
I was struggling two days. This will help someone.

Is Azure Function to Function authentication with MSI supported

I created 2 Azure Function Apps, both setup with Authentication/Authorization so an AD App was created for both. I would like to setup AD Auth from one Function to the other using MSI. I setup the client Function with Managed Service Identity using an ARM template. I created a simple test function to get the access token and it returns: Microsoft.Azure.Services.AppAuthentication: Token response is not in the expected format.
try {
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://myapp-registration-westus-dev.azurewebsites.net/");
log.Info($"Access Token: {accessToken}");
return req.CreateResponse(new {token = accessToken});
}
catch(Exception ex) {
log.Error("Error", ex);
throw;
}
Yes, there is a way to do this. I'll explain at a high level, and then add an item to the MSI documentation backlog to write a proper tutorial for this.
What you want to do is follow this Azure AD authentication sample, but only configure and implement the parts for the TodoListService: https://github.com/Azure-Samples/active-directory-dotnet-daemon.
The role of the TodoListDaemon will be played by a Managed Service Identity instead. So you don't need to register the TodoListDaemon app in Azure AD as instructed in the readme. Just enable MSI on your VM/App Service/Function.
In your code client side code, when you make the call to MSI (on a VM or in a Function or App Service), supply the TodoListService's AppID URI as the resource parameter. MSI will fetch a token for that audience for you.
The code in the TodoListService example will show you how to validate that token when you receive it.
So essentially, what you want to do is register an App in Azure AD, give it an AppID URI, and use that AppID URI as the resource parameter when you make the call to MSI. Then validate the token you receive at your service/receiving side.
Please check that the resource id used "https://myapp-registration-westus-dev.azurewebsites.net/" is accurate. I followed steps here to setup Azure AD authentication, and used the same code as you, and was able to get a token.
https://learn.microsoft.com/en-us/azure/app-service/app-service-mobile-how-to-configure-active-directory-authentication
You can also run this code to check the exact error returned by MSI. Do post the error if it does not help resolve the issue.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
var response = await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), "https://myapp-registration-westus-dev.azurewebsites.net/", "2017-09-01"));
string msiResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
log.Info($"MSI Response: {msiResponse}");
Update:-
This project.json file and run.csx file work for me. Note: The project.json refers to .NET 4.6, and as per Azure Functions documentation (link in comments), .NET 4.6 is the only supported version as of now. You do not need to upload the referenced assembly again. Most probably, incorrect manual upload of netstandard assembly, instead of net452 is causing your issue.
Only the .NET Framework 4.6 is supported, so make sure that your
project.json file specifies net46 as shown here. When you upload a
project.json file, the runtime gets the packages and automatically
adds references to the package assemblies. You don't need to add #r
"AssemblyName" directives. To use the types defined in the NuGet
packages, add the required using statements to your run.csx file.
project.json
{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.Azure.Services.AppAuthentication": "1.0.0-preview"
}
}
}
}
run.csx
using Microsoft.Azure.Services.AppAuthentication;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
try
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://vault.azure.net/");
log.Info($"Access Token: {accessToken}");
return req.CreateResponse(new {token = accessToken});
}
catch(Exception ex)
{
log.Error("Error", ex);
throw;
}
}

Publishing web app to Azure Websites Staging deployment slot fails with webjob

I just created a new deployment slot for my app, imported the publishing profile to Visual Studio, but after deployment I get this error message:
Error 8: An error occurred while creating the WebJob schedule: No website could be found which matches the WebSiteName [myapp__staging] and WebSiteUrl [http://myapp-staging.azurewebsites.net] supplied.
I have 2 webjobs, a continuous and a scheduled webjob.
I already signed in to the correct Azure account, as stated by this answer.
Will I need to set something else up in order to deploy my app to a staging Deployment Slot with webjobs?
My app is using ASP.NET, if it makes a difference?
There are a few quirks when using the Azure Scheduler. The recommendation is to use the new CRON support instead. You can learn more about it here and here.
Jeff,
As David suggested, you can/should migrate to the new CRON support. Here's an example. The WebJob will be deployed as a continuous WebJob.
Keep in mind that in order to use this you need to install the WebJobs package and extensions that are currently a prerelease. You can get them on Nuget.
Install-Package Microsoft.Azure.WebJobs -Pre
Install-Package Microsoft.Azure.WebJobs.Extensions -Pre
Also, as David suggested if you're not using the WebJobs SDK, you can also run this using a settings.job file. He provided an example here.
Program.cs
static void Main()
{
//Set up DI (In case you're using an IOC container)
var module = new CustomModule();
var kernel = new StandardKernel(module);
//Configure JobHost
var storageConnectionString = "your_connection_string";
var config = new JobHostConfiguration(storageConnectionString) { JobActivator = new JobActivator(kernel) };
config.UseTimers(); //Use this to use the CRON expression.
//Pass configuration to JobJost
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
Function.cs
public class Functions
{
public void YourMethodName([TimerTrigger("00:05:00")] TimerInfo timerInfo, TextWriter log)
{
//This Job runs every 5 minutes.
//Do work here.
}
}
You can change the schedule in the TimerTrigger attribute.
UPDATE Added the webjob-publish-settings.json file
Here's an example of the webjob-publiss-settings.json
{
"$schema": "http://schemastore.org/schemas/json/webjob-publish-settings.json",
"webJobName": "YourWebJobName",
"startTime": null,
"endTime": null,
"jobRecurrenceFrequency": null,
"interval": null,
"runMode": "Continuous"
}

Google Drive APi with clean WEB API 2

i wanted to use the Google Drive API along with a simple WEB API 2 - Project.
Somehow the GoogleWebAuthorizationBroker.cs is missing.
What i use:
Visual Studio 2013 Update 4
Empty Template with WEB API
My steps:
Creating the empty project including WEB API
building the project
updating packages via Nuget Packager
Install-Package Google.Apis.Drive.v2 (using this guide: https://developers.google.com/drive/web/quickstart/quickstart-cs)
Copy and Paste the code from the above link into a clean api-controller:
public IEnumerable<string> Get()
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "228492645857-5599mgcfnhrr74a7er1do1chpam4rnbt.apps.googleusercontent.com",
ClientSecret = "onoyJQaUazQK4VsKUjD63sDu",
},
new[] { DriveService.Scope.Drive },
"user",
CancellationToken.None).Result;
// Create the service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",
});
File body = new File();
body.Title = "My document";
body.Description = "A test document";
body.MimeType = "text/plain";
byte[] byteArray = System.IO.File.ReadAllBytes(#"C:\Projects\VS\DataAnime\DataAnime\document.txt");
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, "text/plain");
request.Upload();
File file = request.ResponseBody;
return new string[] { file.Id, "value2" };
}
building
6.1 Error: GoogleWebAuthorizationBroker.cs is missing
6.2 Google says following error in browser:
That’s an error.
Error: redirect_uri_mismatch
Application: Project Default Service Account
You can email the developer of this application at: xxxx#gmail.com
The redirect URI in the request: http://example.com:63281/authorize/ did not match a registered
redirect URI.
http://example.com:63281/authorize/ was neither the url i am using for my project nor the url i registered in my developer console (this errorshowing-port is changeing everytime i run this project.
Has anyone an idea why is that?
No other sources helped fixing this weird issue.
I solved it by creating a new project on https://console.developers.google.com for a native software instead of a web-client project, even i am using a web client.
There is just one weird thing:
If i debug my code, it still says that GoogleWebAuthorizationBroker.cs is missing.
Without debugging i can do everything i want.
Thank you very much for your help.

Open web.config from console application?

I have a console capplication that runs on the same computer that hosts a bunch of web.config files. I need the console application to open each web.config file and decrypt the connection string and then test if the connection string works.
The problem I am running into is that OpenExeConfiguration is expecting a winforms application configuration file (app.dll.config) and OpenWebConfiguration needs to be run through IIS. Since this is my local machine, I'm not running IIS (I use Visual Studio's built-in server).
Is there a way I can open the web.config files while still getting the robustness of .NET's capabilities to decrypt the connectionstrings?
Thanks
Update
The OpenWebConfiguration works if you are querying IIS directly or are the website in question that you want to look up the web.config for. What I am looking to accomplish is the same sort of functionality, but from a console application opening up the web.config file of a website on my same machine not using an IIS query because IIS isn't running on my machine.
Ok I got it... compiled and accessed this so i know it works...
VirtualDirectoryMapping vdm = new VirtualDirectoryMapping(#"C:\test", true);
WebConfigurationFileMap wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
// Get the Web application configuration object.
Configuration config = WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
ProtectSection(config, #"connectionStrings", "DataProtectionConfigurationProvider");
This is assuming you have a file called web.config in a directory called C:\Test.
I adjusted #Dillie-O's methods to take a Configuration as a parameter.
You must also reference System.Web and System.configuration and any dlls containing configuration handlers that are set up in your web.config.
The when the ConfigurationManager class grab a section from the config file, it has an "IsProtected" property that it can infer for a given section that you grab. If it is protected, you can then Unprotect it using some code.
The basic method for encrypting/decrypting goes like this (taken from article link below):
private void ProtectSection(string sectionName, string provider)
{
Configuration config =
WebConfigurationManager.
OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section =
config.GetSection(sectionName);
if (section != null &&
!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection(provider);
config.Save();
}
}
private void UnProtectSection(string sectionName)
{
Configuration config =
WebConfigurationManager.
OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section =
config.GetSection(sectionName);
if (section != null &&
section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
config.Save();
}
}
Check out this article for the full details on working with this.
public static string WebKey(string key)
{
var configFile = new System.IO.FileInfo(webconfigPath);
var vdm = new VirtualDirectoryMapping(configFile.DirectoryName, true, configFile.Name);
var wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
System.Configuration.Configuration config = WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
System.Configuration.AppSettingsSection appSettingSection = (System.Configuration.AppSettingsSection)config.GetSection("appSettings");
System.Configuration.KeyValueConfigurationElement kv = appSettingSection.Settings.AllKeys
.Where(x => x.Equals(key))
.Select(x => appSettingSection.Settings[key])
.FirstOrDefault();
return kv != null ? kv.Value : string.Empty;
}
I think you want to use WebConfigurationManager class with its OpenWebConfiguration method.
It takes a path to the web.config and should open it just like it would in a HTTPContext based application.

Resources