I use MEF to extend my web application and I use the following folder structure
> bin
> extensions
> Plugin1
> Plugin2
> Plugin3
To achive this automatically, the plugin projects output paths are set to these directories. My application is working with and without azure. My problem is now, that it seems to be inpossible to include the extensions subdirectory automatically to the azure deployment package.
I've tried to set the build dependencies too, without success.
Is there another way?
Well,
I've struggled with the bin folder. The issue (if we may say "issue") is that the packaging process, just packs what is "copy to out directory" set to "copy if newer/aways" only for the Web application (Web Role) project. Having another assemblies in the BIN which are not explicitly referenced by the Web Application will not get deployed.
For my case, where I have pretty "static" references I just pack them in a ZIP, put them in a BLOB container and then use the Azure Bootstrapper to download, extract and put in the BIN folder these references. However, because I don't know the actual location of the BIN folder in a startup task, I use helper wrappers for the bootstrapper to make the trick.
You will need to get the list of local sites, which can be accomplished by something similar to:
public IEnumerable<string> WebSiteDirectories
{
get
{
string roleRootDir = Environment.GetEnvironmentVariable("RdRoleRoot");
string appRootDir = (RoleEnvironment.IsEmulated) ? Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory) : roleRootDir;
XDocument roleModelDoc = XDocument.Load(Path.Combine(roleRootDir, "RoleModel.xml"));
var siteElements = roleModelDoc.Root.Element(_roleModelNs + "Sites").Elements(_roleModelNs + "Site");
return
from siteElement in siteElements
where siteElement.Attribute("name") != null
&& siteElement.Attribute("name").Value == "Web"
&& siteElement.Attribute("physicalDirectory") != null
select Path.Combine(appRootDir, siteElement.Attribute("physicalDirectory").Value);
}
}
Where the _roleModelNs variable is defined as follows:
private readonly XNamespace _roleModelNs = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition";
Next you will need something similar to that method:
public void GetRequiredAssemblies(string pathToWebBinfolder)
{
string args = string.Join("",
#"-get https://your_account.blob.core.windows.net/path/to/plugin.zip -lr $lr(temp) -unzip """,
pathToWebBinfolder,
#""" -block");
this._bRunner.RunBootstrapper(args);
}
And the RunBootstrapper has following signature:
public bool RunBootstrapper (string args)
{
bool result = false;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = this._bootstrapperPath;
psi.Arguments = args;
Trace.WriteLine("AS: Calling " + psi.FileName + " " + psi.Arguments + " ...");
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
// run elevated
// psi.Verb = "runas";
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(psi))
{
exeProcess.PriorityClass = ProcessPriorityClass.High;
string outString = string.Empty;
// use ansynchronous reading for at least one of the streams
// to avoid deadlock
exeProcess.OutputDataReceived += (s, e) =>
{
outString += e.Data;
};
exeProcess.BeginOutputReadLine();
// now read the StandardError stream to the end
// this will cause our main thread to wait for the
// stream to close
string errString = exeProcess.StandardError.ReadToEnd();
Trace.WriteLine("Process out string: " + outString);
Trace.TraceError("Process error string: " + errString);
result = true;
}
}
catch (Exception e)
{
Trace.TraceError("AS: " + e.Message + e.StackTrace);
result = false;
}
return result;
}
Of course, in your case you might want something a bit more complex, where you'll first try to fetch all plugins (if each plugin is in its own ZIP) via code, and then execute the GetRequiredAssemblies multiple times for each plugin. And this code might be executing in the RoleEntryPoint's OnStart method.
And also, if you plan to be more dynamic, you can also override the Run() method of your RoleEntryPoint subclass, and check for new plugins every minute for example.
Hope this helps!
EDIT
And how can you get the plugins deployed. Well, you can either manually upload your plugins, or you can develop a small custom BuildTask to automatically upload your plugin upon build.
Related
I am currently building a WinForms app and I need to create a bin file
in which I will serialize data. I let the user choose in which folder he wants the file to be saved in, but if he doesn't choose anything I want to save the file in a default path.
The thing is, I am not so familiar with windows' file system, and I am unable to find a good folder to save the file in.
My requirements from such folder are:
All windows computers should have it
The path to this folder all windows computer is the same
Is used for programs' auto-generated files as an "international default"
Not used frequently by the user (a "just don't touch" folder)
what is the common solution for such things?
You cas use a dedicated common ProgramData folder:
string CommonAppDataFolderPath
= Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
+ Path.DirectorySeparatorChar
+ AssemblyCompany
+ Path.DirectorySeparatorChar
+ AssemblyTitle
+ Path.DirectorySeparatorChar;
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if ( attributes.Length == 0 )
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
public string AssemblyTitle
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if ( attributes.Length > 0 )
{
AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
if ( titleAttribute.Title != "" )
{
return titleAttribute.Title;
}
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
}
}
It is AppData and you can get it with Environment.GetFolderPath:
(Environment is in System.IO namespace)
string binPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SomeAppName");
// this will return something like this:
// C:\Users\SomeUserName\AppData\Roaming\SomeAppName
You can use System.Reflection to identify a path in the debug or release folder of your assembly:
public static string Path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "someapp");
I am trying to create a simple Xamarin forms app which allows the user to browse for or take a photo and have azure cognitive services tag the photo using a custom vision model.
I am unable to get the client to successfully authenticate or find a resource per the error message in the exception produced by the VisionServiceClient. Am I missing something? What would be the correct values to use for the arguments to VisionServiceClient?
All keys have been removed from the below images, they are populated.
Exception thrown in VS2017:
'Microsoft.ProjectOxford.Vision.ClientException' in System.Private.CoreLib.dll
Call to VisionServiceClient:
private const string endpoint = #"https://eastus2.api.cognitive.microsoft.com/vision/prediction/v1.0";
private const string key = "";
VisionServiceClient visionClient = new VisionServiceClient(key, endpoint);
VisualFeature[] features = { VisualFeature.Tags, VisualFeature.Categories, VisualFeature.Description };
try
{
AnalysisResult temp = await visionClient.AnalyzeImageAsync(imageStream,
features.ToList(), null);
return temp;
}
catch(Exception ex)
{
return null;
}
VS Exception Error:
Azure Portal for cognitive services:
Custom Vision Portal:
It looks like you're confusing the Computer Vision and the Custom Vision APIs. You are attempting to use the client SDK for the former using the API key of the latter.
For .NET languages, you'll want the Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction NuGet package.
Your code will end up looking something like this:
ICustomVisionPredictionClient client = new CustomVisionPredictionClient()
{
ApiKey = PredictionKey,
Endpoint = "https://southcentralus.api.cognitive.microsoft.com"
};
ImagePrediction prediction = await client.PredictImageAsync(ProjectId, stream, IterationId);
Thank you to cthrash for the extended help and talking with me in chat. Using his post along with a little troubleshooting I have figured out what works for me. The code is super clunky but it was just to test and make sure I'm able to do this. To answer the question:
Nuget packages and classes
Using cthrash's post I was able to get both the training and prediction nuget packages installed, which are the correct packages for this particular application. I needed the following classes:
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction.Models
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models
Endpoint Root
Following some of the steps Here I determined that the endpoint URL's only need to be the root, not the full URL provided in the Custom Vision Portal. For instance,
https://southcentralus.api.cognitive.microsoft.com/customvision/v2.0/Prediction/
Was changed to
https://southcentralus.api.cognitive.microsoft.com
I used both the key and endpoint from the Custom Vision Portal and making that change I was able to use both a training and prediction client to pull the projects and iterations.
Getting Project Id
In order to use CustomVisionPredictionClient.PredictImageAsync you need a Guid for the project id and an iteration id if a default iteration is not set in the portal.
I tested two ways to get the project id,
Using project id string from portal
Grab the project id string from the portal under the project settings.
For the first argument to PredictImageAsync pass
Guid.Parse(projectId)
Using the training client
Create a new CustomVisionTrainingClient
To get a list of <Project> use
TrainingClient.GetProjects().ToList()
In my case I only had a single project so I would just need the first element.
Guid projectId = projects[0].Id
Getting Iteration Id
To get the iteration id of a project you need the CustomVisionTrainingClient.
Create the client
To get a list of <Iteration> use
client.GetIterations(projectId).ToList()
In my case I had only a single iteration so I just need the first element.
Guid iterationId = iterations[0].Id
I am now able to use my model to classify images. In the code below, fileStream is the image stream passed to the model.
public async Task<string> Predict(Stream fileStream)
{
string projectId = "";
//string trainingEndpoint = "https://southcentralus.api.cognitive.microsoft.com/customvision/v2.2/Training/";
string trainingEndpoint = "https://southcentralus.api.cognitive.microsoft.com/";
string trainingKey = "";
//string predictionEndpoint = "https://southcentralus.api.cognitive.microsoft.com/customvision/v2.0/Prediction/";
string predictionEndpoint = "https://southcentralus.api.cognitive.microsoft.com";
string predictionKey = "";
CustomVisionTrainingClient trainingClient = new CustomVisionTrainingClient
{
ApiKey = trainingKey,
Endpoint = trainingEndpoint
};
List<Project> projects = new List<Project>();
try
{
projects = trainingClient.GetProjects().ToList();
}
catch(Exception ex)
{
Debug.WriteLine("Unable to get projects:\n\n" + ex.Message);
return "Unable to obtain projects.";
}
Guid ProjectId = Guid.Empty;
if(projects.Count > 0)
{
ProjectId = projects[0].Id;
}
if (ProjectId == Guid.Empty)
{
Debug.WriteLine("Unable to obtain project ID");
return "Unable to obtain project id.";
}
List<Iteration> iterations = new List<Iteration>();
try
{
iterations = trainingClient.GetIterations(ProjectId).ToList();
}
catch(Exception ex)
{
Debug.WriteLine("Unable to obtain iterations.");
return "Unable to obtain iterations.";
}
foreach(Iteration itr in iterations)
{
Debug.WriteLine(itr.Name + "\t" + itr.Id + "\n");
}
Guid iteration = Guid.Empty;
if(iterations.Count > 0)
{
iteration = iterations[0].Id;
}
if(iteration == Guid.Empty)
{
Debug.WriteLine("Unable to obtain project iteration.");
return "Unable to obtain project iteration";
}
CustomVisionPredictionClient predictionClient = new CustomVisionPredictionClient
{
ApiKey = predictionKey,
Endpoint = predictionEndpoint
};
var result = await predictionClient.PredictImageAsync(Guid.Parse(projectId), fileStream, iteration);
string resultStr = string.Empty;
foreach(PredictionModel pred in result.Predictions)
{
if(pred.Probability >= 0.85)
resultStr += pred.TagName + " ";
}
return resultStr;
}
I created a class that connected to the API to retrieve the required data using httpclient. That file was called in the code behind file of the view and worked perfectly. Than I decided to implement the MVVM approach. As a result, I moved the code that initialized the rest service class to the view-model.
After doing that, i stopped getting the data. To investigate, I stated the the debugging session with the breakpoint placed at the line where i initialize the rest service class. Than i executed that line. By doing that, I found out that a huge android mono exception is thrown and the debugging session if stopped. The app exits the debugging session.
This has happened for the first time since i stated developing my app in Xamarin Forms. I have no idea about why it is breaking like that. Your help will be greatly appreciated.
This is the code that was working properly.
In the view code behind file
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SubtaskPage : ContentPage
{
protected override void OnAppearing()
{
base.OnAppearing();
PopulateSubtaskData();
}
private async void PopulateSubtaskData()
{
lstSubtasks.IsRefreshing = true;
try
{
RestService rs = new RestService();
SResponse = await rs.GetSubtasksAsync(Convert.ToInt32(Application.Current.Properties["UserId"]));
if (SResponse.Status == 1)
{
lstSubtasks.ItemsSource = SResponse.Subtasks;
}
else
{
await DisplayAlert("Error", SResponse.Message, "Ok");
}
}
catch (Exception E)
{
Debug.WriteLine(#"GetSubtasksAsync -> ERROR {0}", E.Message);
}
lstSubtasks.IsRefreshing = false;
}
}
The rest service class is as follows
This class is in a separate folder named "Services". ip and url have been changed for security reason.
class RestService
{
HttpClient client;
public List<Ticket> Tickets { get; private set; }
string Server1 = "server ip";
string Server2 = "server ip";
public RestService()
{
client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
}
public async Task<SubtasksResponse> GetSubtasksAsync(int UserId)
{
SubtasksResponse SubtaskResponse = new SubtasksResponse();
string ApiUrl = "URL";
string Url = "";
HttpResponseMessage response;
if (CrossConnectivity.Current.IsConnected)
{
Url = await GetActiveServerAsync();
if (Url != "")
{
var uri = string.Format(Url + ApiUrl, UserId);
try
{
response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
SubtaskResponse.Subtasks = JsonConvert.DeserializeObject<List<Ticket>>(content);
SubtaskResponse.Status = 1;
}
else
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "Attempt to fetch data from server was unsuccessful. Please try again";
}
}
catch (Exception E)
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "Error occured while fetching data from the server. Please try again";
}
}
else
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "Remote Server Not Responding! Please try again later";
}
}
else
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "No Network Connection Found! Please connect to a network and try again";
}
return SubtaskResponse;
}
}
}
This was working fine until I added the view model into the mix.
This is how I am calling the function in the view model.
async Task<SubtasksResponse> PopulateSubtaskList()
{
RestService rs = new RestService();
IsBusy = true;
_subtaskList = await rs.GetSubtasksAsync(Convert.ToInt32(Application.Current.Properties["UserId"]));
IsBusy = false;
return _subtaskList;
}
"RestService rs = new RestService();" this is the line where the code breaks.
Here is the image of the exception that occurs when the code breaks.
Hope you get the clear picture of the situation. Please let me know if additional information is required.
Thanks
Don't do this. If you want to call rest from a mvvm Xamarin Forms app I can advice Refit. All the difficult work is already done for you and abstracted away. With a few lines of code you are up and running.
BTW the error message you are showing probably has nothing to do with your code but is a bug in a recent Xamarin version. See here: https://bugzilla.xamarin.com/show_bug.cgi?id=56787
Found the answer on this page (https://releases.xamarin.com/common-issues-in-the-xamarin-15-2-2-release-being-tracked-by-the-xamarin-team/).
The solution is as follows
Download the missing Mono.Posix file and unzip the archive.
Right-click the Mono.Posix.dll file in Explorer and select Properties.
Check the Digital Signatures tab to ensure the file shows a valid Xamarin Inc. signature.
At the bottom of the General tab, if an Unblock checkbox appears, enable it and select OK. (This checkbox appears depending on how the file was downloaded.)
For Visual Studio 2017, copy the Mono.Posix.dll file into the “Xamarin.VisualStudio” extension directory. For example, for a default installation of the Enterprise edition, copy the file into:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Xamarin.VisualStudio
For Visual Studio 2015, copy the file into the “Xamarin\Xamarin” extension directory:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\
Quit and restart Visual Studio.
For more detail, visit the link given above.
I am ruing my website on azure, every folder is present on site directory in azure but uploadimages is my sub folder of content is absent from wwwroot, and images is not uploading also
I am using
var path =Path.Combine(Server.MapPath("~/Content/UploadImages/")+filename);
same with document upload
According to your description, I have tested on my side, please follow below to find out whether it could help you.
As you said, you got the target file path by this code:
var path = Path.Combine(Server.MapPath("~/Content/UploadImages/") + filename);
Before uploading files, please make sure that the directory in your web server “~/Content/UploadImages/” is existed.
Here is my test code:
MVC controller method
[HttpPost]
public JsonResult UploadFiles()
{
try
{
foreach (string file in Request.Files)
{
var fileContent = Request.Files[file];
if (fileContent != null && fileContent.ContentLength > 0)
{
var stream = fileContent.InputStream;
var fileName = Path.GetFileName(fileContent.FileName);
string baseDir = Server.MapPath("~/Content/UploadImages/");
if (!Directory.Exists(baseDir))
Directory.CreateDirectory(baseDir);
var path = Path.Combine(baseDir, fileName);
using (var fileStream = System.IO.File.Create(path))
{
stream.CopyTo(fileStream);
}
}
}
}
catch (Exception e)
{
return Json(new
{
Flag = false,
Message = string.Format("File Uploaded failed with exception:{0}", e.Message)
});
}
return Json(new
{
Flag = true,
Message = "File uploaded successfully!"
});
}
Additionally, for long-term consideration, you could store your files on Azure Blob Storage which could bring you some benefits, such as:
1.Serving images or documents directly to a browser
2.Storing files for distributed access
3.When you scale up your site, your site could run in multiple Web Server instances which could access the same files & docs simultaneously
For more details, please refer to this link: https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/
I'm trying to build a report to show the relative efficiency of my various build agents and having trouble getting the info I need out of the tool.
What I'd like to have is a simple grid with the following columns:
Build Number
Build Definition
Build Agent
Build Status
Build Start Time
Build Duration
Which would let me do something like chart the duration of successful builds of a given build definition on agent1 against the same build definition on agent2 through agentN.
How would I go about this?
My initial intention was to point you to TFS OLAP Cube & describe how you could retrieve what you were after. Then I realized that the cube does not provide with the info which Agent built what Build.Then I thought it would be simple to write a small TFS-console app that print the infos you 're after:
using System;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
namespace BuildDetails
{
class Program
{
static void Main()
{
TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFS:8080/tfs/CoLLeCtIoNNaMe"));
var buildService = (IBuildServer)teamProjectCollection.GetService(typeof(IBuildServer));
IBuildDefinition buildDefinition = buildService.GetBuildDefinition("TeamProjectName", "BuildDefinitionName");
IBuildDetail[] buildDetails = buildService.QueryBuilds(buildDefinition);
foreach (var buildDetail in buildDetails)
{
Console.Write(buildDetail.BuildNumber+"\t");
Console.Write(buildDefinition.Name+"\t");
Console.Write(buildDetail.BuildAgent.Name+"\t");
Console.Write(buildDetail.Status+"\t");
Console.Write(buildDetail.StartTime+"\t");
Console.WriteLine((buildDetail.FinishTime - buildDetail.StartTime).Minutes);
}
}
}
}
This won't compile, since
Eventually I dove into the IBuildInformationNode[] and got the build agent as follows:
IBuildInformation buildInformation = buildDetail.Information;
IBuildInformationNode[] buildInformationNodes = buildInformation.Nodes;
string agentName;
try
{
agentName = buildInformationNodes[0].Children.Nodes[3].Fields["ReservedAgentName"];
}
catch
{
agentName = "Couldn't determine BuildAgent";
}
Console.Write(agentName + "\t");
The try-catch is necessary, so you can deal with builds that failed/stopped before agent-selection.If you use this latter part as a substitute to the failing Console.Write(buildDetail.BuildAgent.Name+"\t"); you should end up with a console app, whose output can be piped into a *.CSV file & then imported to Excel.
The following code should help in getting the Build Agent Name for the given build detail.
private string GetBuildAgentName(IBuildDetail build)
{
var buildInformationNodes = build.Information.GetNodesByType("AgentScopeActivityTracking", true);
if (buildInformationNodes != null)
{
var node = buildInformationNodes.Find(s => s.Fields.ContainsKey(InformationFields.ReservedAgentName));
return node != null ? node.Fields[InformationFields.ReservedAgentName] : string.Empty;
}
return string.Empty;
}
Make sure that you have refresh the build information in the build details object.You can do so by the either calling the following code on your build Details object before getting the build agents
string[] refreshAllDetails = {"*"};
build.Refresh(refreshAllDetails, QueryOptions.Agents);
Hope it helps :)
The build agent information isn't always in the same place.
I found it for a build I was looking at in buildInformationNodes[1].Children.Nodes[2].Fields["ReservedAgentName"]. The following seems to work for me (so far).
private static string GetAgentName(IBuildDetail buildDetail)
{
string agentName = "Unknown";
bool fAgentFound = false;
try
{
foreach (IBuildInformationNode node in buildDetail.Information.Nodes)
{
foreach (IBuildInformationNode childNode in node.Children.Nodes)
{
if (childNode.Fields.ContainsKey("ReservedAgentName"))
{
agentName = childNode.Fields["ReservedAgentName"];
break;
}
}
if (fAgentFound) break;
}
}
catch (Exception ex)
{
// change to your own routine as needed
DumpException(ex);
}
return agentName;
}