I have a C# class that does an address lookup. I want to expose this as an Azure function. I've been going through the documentation but can't see how I can/if it's possible to do the following:
I have a Git repository in Team Services that contains a class library of my AddressLookup. Can my Function reference this project?
If I look at the folder structure of the site I can see it has copied over all the source files from the Git repository, can I get it to build the solution or does it literally just pull all the files?
Where in the solution do I put the function? Do I create a solution folder of the name of the function and place the relevant files in there?
My AddressLookup class returns an object that is defined in the class library. Will the function be able to use and return this?
Thanks
Alex
Follow-up to Q1: Are you trying to setup CI? For continuous integration with Azure Functions, you may reference the following:
https://azure.microsoft.com/en-us/documentation/articles/functions-continuous-deployment/#setting-up-continuous-deployment
http://flgmwt.github.io/azure/azure-functions/c-sharp/2016/04/04/azure-fns-with-ci.html
--Update 10/17--
Specific to Team Services, here are the steps:
Make sure that your VSTS account is linked to your Azure Subscription. Follow the instructions in this article.
Navigate to the Functions Portal for your Function App and click on Function app Settings -> Configure continuous integration.
In the Deployements blade, click on Setup and configure your Deployment source information (see sample snapshot below). Click on the OK button. Wait for the sync to succeed. Close the Deployments blade.
Give it a minute and refresh your Functions Portal session. You should now see the function added to your Function site. The snapshot below is my AddressLookup function that was synced from my Team Services project named MyFirstProject.
Note the disclaimer message above the Code editor. If you hook up CI for your Function, you will not be able to edit it in the Functions Portal. Since this particular example requires a request body, you will need to test it using Postman.
--End of update 10/17--
Answer to Q2:
Here's a good documentation describing the folder structure of Azure Functions:
https://azure.microsoft.com/en-us/documentation/articles/functions-reference/
I also recommend the follow-up documentation specific to C# development for Azure Functions:
https://azure.microsoft.com/en-us/documentation/articles/functions-reference-csharp/
Answer to Q3 & Q4: I will attempt to answer these by providing a sample implementation. I don't have any context on the implementation of your AddressLookup library, however, in the interest of providing an example, I am going to take a wild leap and assume that it is a library that will perform some Geocoding operations. Assuming again that you want to use this library in an HTTP-triggered Function, you may begin by first generating the AddressLookup.dll and then uploading it to the bin folder inside your Function. You may then reference that DLL from your Function script.
For instance, using this article as a reference, I generated a AddressLookup.dll library in Visual Studio that has the following implementation. This DLL will serve as a proxy for your AddressLookup library so that I can demonstrate how we can use it in a Function.
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Xml.Linq;
namespace AddressLookup
{
public class GeoLocation
{
public double Longitude { get; set; }
public double Latitude { get; set; }
}
public class GeoCoder
{
private const string geoCodeLookupUrlPattern =
"https://maps.googleapis.com/maps/api/geocode/xml?address={0}&key={1}";
private const string addressLookupUrlPattern =
"https://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&key={2}";
private string _apiKey = null;
public GeoCoder(string apiKey)
{
if (string.IsNullOrEmpty(apiKey))
{
throw new ArgumentNullException("apiKey");
}
_apiKey = apiKey;
}
public GeoLocation GetGeoLocation(string address)
{
GeoLocation loc = null;
string encodedAddress = HttpUtility.UrlEncode(address);
string url = string.Format(geoCodeLookupUrlPattern, encodedAddress, _apiKey);
WebRequest request = WebRequest.Create(url);
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
XDocument document = XDocument.Load(new StreamReader(stream));
XElement longitudeElement = document.Descendants("lng").FirstOrDefault();
XElement latitudeElement = document.Descendants("lat").FirstOrDefault();
if (longitudeElement != null && latitudeElement != null)
{
loc = new GeoLocation
{
Longitude = Double.Parse(longitudeElement.Value, CultureInfo.InvariantCulture),
Latitude = Double.Parse(latitudeElement.Value, CultureInfo.InvariantCulture)
};
}
}
}
}
return loc;
}
public string GetAddress(GeoLocation loc)
{
string address = null;
string url = string.Format(addressLookupUrlPattern, loc.Latitude, loc.Longitude, _apiKey);
WebRequest request = WebRequest.Create(url);
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
XDocument document = XDocument.Load(new StreamReader(stream));
XElement element = document.Descendants("formatted_address").FirstOrDefault();
if (element != null)
{
address = element.Value;
}
}
}
}
return address;
}
}
}
Now, let's create an HTTP-Triggered Function by performing the following steps:
Go to the Functions Portal. Create a Function using the HTTP
Trigger - C# template.
Fill in the name (e.g., AddressLookup) and authorization level (e.g., Anonymous). You should now see a Function named AddressLookup created with some pre-populated code.
On the left pane, click on the Function app settings button.
Optional: Click on Configure app Settings. Under the "App settings" section, add a value for the key GoogleMapsAPIKey with your api key, then click on the Save button. Note: If you skip this step, then you will need to hard-code the key in your function code later.
Next, use the Kudu console to upload your DLL. Click on the Go to Kudu button. This will launch a new browser window
with a cmd console. Type the following to navigate to your
Function directory,
cd site\wwwroot\AddressLookup
Create a bin folder by typing mkdir bin at the command prompt as follows,
Double-click on the bin folder and upload (see "Add files") the AddressLookup.dll into the folder. When you are done, you should a similar snapshot below,
Go back to the Functions Portal. In your Function's editor, at the bottom of the Code section, click on View Files. You should now see the newly created bin folder as follows,
Replace the contents of the pre-populated Function script with the following code
#r "AddressLookup.dll"
using System;
using AddressLookup;
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
// Reading environment variable from App Settings, replace with hardcoded value if not using App settings
string apiKey = System.Environment.GetEnvironmentVariable("GoogleMapsAPIKey", EnvironmentVariableTarget.Process);
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
string address = data?.address;
string name = data?.name;
GeoCoder geoCoder = new GeoCoder(apiKey);
GeoLocation loc = geoCoder.GetGeoLocation(address);
string formattedAddress = geoCoder.GetAddress(loc);
HttpResponseMessage message = null;
if (name == null)
{
message = req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name in the request body");
}
else
{
var msg = $"Hello {name}. Lon: '{loc.Longitude}', Lat: '{loc.Latitude}', Formatted address: '{formattedAddress}'";
message = req.CreateResponse(HttpStatusCode.OK, msg);
}
return message;
}
Click on the Save button.
In the "Run" section, supply the following request body,
{
"name": "Azure",
"address": "One Microsoft Way Redmond WA 98052"
}
Click on the Run button.
You should see some log entries similar to the following,
2016-10-15T03:54:31.538 C# HTTP trigger function processed a request. RequestUri=https://myfunction.azurewebsites.net/api/addresslookup
2016-10-15T03:54:31.773 Function completed (Success, Id=e4308c0f-a615-4d43-8b16-3a6afc017f73)
and the following HTTP response message,
"Hello Azure. Lon: '-122.1283833', Lat: '47.6393225', Formatted address: '1 Microsoft Way, Redmond, WA 98052, USA'"
Since this is a HTTP-triggered Function, you may also test your Function using Postman. See snapshot below,
If you upload your own DLL in step 5 and edit the Function code to call your library, the Function should work just as well.
Is the assembly you want to reference frozen, or do you want to see updates? If you don't want to see updates, see the answer by Ling Toh.
But if you want to see updates when the assembly updates:
Link your function to a some form of continuous delivery. The official documentation explains how to do this. At the moment, you seem to need a separate git repository, VSTS project (or whatever) to do this easily. (It is possible to edit the deployment process in Kudu, but I would avoid that if you possibly can).
The functions project should contain only the functions code themselves. So it should contain something like the followling:
global.json
host.json
packages.config
Web.config
function1/
function1/run.csx
function1/project.json
function1/function.json
Where you should replace function1 by the name of your function.
Once you've configured this to push to your functions host, you're most of the way to where you want to be. Next, add a function1/run subdirectory where you place yourAssembly.dll. This should be automatically copied here on a successful build of the assembly project. I don't have experience of VSTS to know exactly the best way to do this, so you might need to ask another question.
You've now placed the assembly in the right place. You now refer to it by adding the assembly reference line to the top of your run.csx:
#r "yourAssembly.dll"
Note that all of the references have to be before everything else at the top of the run.csx. So you can put it after other references, but it has to be before anythign else, including load specifications.
Note that for custom assemblies you include the .dll and quote the file, whereas for framework assemblies that aren't referenced by default, you don't
In an ideal world, this will be enough.
But functions doesn't trigger a rebuild if the assembly is updated at the moment, only if project.json, run.csx or function.json is updated. So as part of this process, I then look at the end of the file and add or remove a blank line. It needs to be meaningless (so that you're not changing something important), but enough for your version control tool to think that the file has changed. Clearly, this step is not necessary if you've also made other changes to the file.
If you're using git, you'd now commit and push the changes up. Functions will see that function has changed, and recompile. You should see this in the log pane in the function itself.
Note that if you have two functions using the same dependent assembly, you need to copy it into both function folders; this can't be shared.
I am trying to use the SFAutoComplete control from SyncFusion in a Xamarin iPad app. (only iPad).
I am not able to get any sort of change event to fire.
What I've tried:
If you download SyncFusion and install it, it comes with a "SampleBrowser" app that has samples for all the controls in the suite.
If you open that SampleBrowser in visual studio and open the AutoComplete_Tablet.cs file after line 97, I've added this code:
countryAutoComplete.ValueChanged += (sender, args) =>
{
suggestionModeLabel.Text = "IT WORKED!";
};
But it never fires.
I've tried to use several different events from the list of events this control has (partial list from screenshot):
None of them seem to fire (I haven't tried ALL of them).
What do I need to do to get one of these events to fire? What am I missing?
Thanks for using Syncfusion Controls.
Delegate property can be used to hook the SFAutoComplete's events as per in the following code example,
Declaration code for Delegate property
SFAutoComplete autocomplete = new SFAutoComplete();
autocomplete.Delegate = new SFAutoCompleteDelegate();
The way to hook the events in SFAutoComplete
public class SFAutoCompleteDelegate : AutoCompleteDelegate
{
public override void DidTextChange(SFAutoComplete SFAutoComplete, string value)
{
//It fired while changing the text in AutoComplete
}
public override void DidSelectionChange(SFAutoComplete SFAutoComplete, string value)
{
//It fired while changing the suggestion from suggestion box.
}
}
We have created a sample for achieving your requirement. Please download the same from the following link
Link:http://www.syncfusion.com/downloads/support/forum/125261/ze/testingAutoComplete_21799375630
Thanks & Regards,
Hemalatha M.R
I am using selenium version 2.45 with internet explorer 11 and works well
but i have problem in assert function and tr and catch they aren't included!!
so how can i start maybe i did something wrong btw i start with console application and added reference (Selenium WebDriver, Selenium WebDriver Support Classes, WebDriver-backed Selenium, Selenium Remote Control.)
if there is something wrong kindly tell me how can i start from first
-my code open google and search for amazon then open amazon and search for something invalid i want make it return that there is no data find
so how can i search for text on page line "did not match"
thanks in advance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Diagnostics;
using System.Collections;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Interactions;
class GoogleSuggest
{
static void Main(string[] args)
{
IWebDriver driver = new InternetExplorerDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(20));
driver.Navigate().GoToUrl("http://www.google.com/");
driver.FindElement(By.Id("lst-ib")).SendKeys("amazon");
driver.FindElement(By.Id("lst-ib")).SendKeys(Keys.Enter);
driver.FindElement(By.ClassName("r")).Click();
driver.FindElement(By.Id("twotabsearchtextbox")).SendKeys("akajerhfbds bvksajhgrcbskhb");
driver.FindElement(By.Id("twotabsearchtextbox")).SendKeys(Keys.Enter);
Thread.Sleep(6000);
driver.Quit();
}
}
I did a search on Amazon for "asdvasdv" - inspecting the elements, there is one with an id of "noResultsTitle" - if Amazon is consist with this you can use
FindElement(By.CssSelector("[id*='noResults']"))
I've created the check-in policy from this MSDN article as an example (code is just copy / pasted).
This works fine, it appears when I try and do a check-in, however it appears as an warning. So I can ignore it by just pressing Check In again. How can I change the code, as listed in the URL, so that it will return an Error not a warning. I can't see any properties on PolicyFailure to do this.
Essentially I want it to look like the error in this screenshot:
Image Source
EDIT: Here is the exact code that I'm using. Now it is slightly modified from the original source, but not in any massive way I wouldn't have thought. Unfortunately I can't post screenshots, but I'll try and describe everything I've done.
So I have a DLL from the code below, I've added it into a folder at C:\TFS\CheckInComments.dll. I added a registry key under Checkin Policies with the path to the DLL, the string value name is the same as my DLL (minus .dll). In my project settings under source control I've added this Check-In Policy.
It all seems to work fine, if I try and do a check-in it will display a warning saying "Please provide some comments about your check-in" which is what I expect, what I'd like is for it to stop the check-in if any policies are not met, however I would still like the user to be able to select Override if necessary. At the moment, even though there is a warning, if I was to click the Check In button then it would successfully check-in the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace CheckInComments
{
[Serializable]
public class CheckInComments : PolicyBase
{
public override string Description
{
get
{
return "Remind users to add meaningful comments to their checkins";
}
}
public override string InstallationInstructions
{
get { return "To install this policy, read InstallInstructions.txt"; }
}
public override string Type
{
get { return "Check for Comments Policy"; }
}
public override string TypeDescription
{
get
{
return "This policy will prompt the user to decide whether or not they should be allowed to check in";
}
}
public override bool Edit(IPolicyEditArgs args)
{
return true;
}
public override PolicyFailure[] Evaluate()
{
string proposedComment = PendingCheckin.PendingChanges.Comment;
if (String.IsNullOrEmpty(proposedComment))
{
PolicyFailure failure = new PolicyFailure("Please provide some comments about your check-in", this);
failure.Activate();
return new PolicyFailure[1]
{
failure
};
}
else
{
return new PolicyFailure[0];
}
}
public override void Activate(PolicyFailure failure)
{
MessageBox.Show("Please provide comments for your check-in.", "How to fix your policy failure");
}
public override void DisplayHelp(PolicyFailure failure)
{
MessageBox.Show("This policy helps you to remember to add comments to your check-ins", "Prompt Policy Help");
}
}
}
A check-in policy will always return a warning and if your user has permission to ignore them, then they can.
Users can always override the policy. You can query the TFS warehouse to generate a report of users violating the policies and their reasons for the violation if they provided any. Or setup an alert whenever someone ignores these polite warnings.
There is no way to enforce this from the policy itself. Only from a server side plugin, as described by Neno in the post you quoted. Such a server side plugin can be created for 2012 or 2010 as well. The process is explained here.
I just got past that issue by turning on Code Analysis on my project - right click on your project, click properties, go to Code Analysis, select the Configuration drop down and pick "All Configurations", select the "Enable Code Analysis on Build".
Do a build and make sure you have no errors / warnings.
This will get you past any policies requiring code analysis on build.
I am new to codedUI and for a start I am reading a lot about what should be a best practice.
I have read that if you are using complex application that is advisable to use multiple UImaps. Although I can not see a benefit at the moment I have created small project with two UImaps.
In the first initial setup (with initial UImap and CodedUITest1) I can choose whether to use Test builder or existing action recording for generating code. What ever I do it 'goes' to initial UImap. When I create new UI, test builder is started and I can record some actions and when I save it, it is added to newly created UImap in my case called AdvanceSettings. But I can not generate code from existing recording. Why is that? I would like to create automated test cases based on manual test cases with recordings.
Below is my code. I am using CodedUITest1 class for both UImaps. Should I use new class for
every UImap?
If you have some comments on code please do write some.
As I see it. Multiple UImaps are used if you have complex application so you can more easily change something. every GUI element has one UImap so if something changes on that GUI you only edit that UImap. But if you have one UImap and you use proper naming you can also easily replace or re-record certain method. So I am missing big picture with multiple UImaps.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows.Input;
using System.Windows.Forms;
using System.Drawing;
using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UITest.Extension;
using Keyboard = Microsoft.VisualStudio.TestTools.UITesting.Keyboard;
using EAEP.AdvanceSettingsClasses;
namespace EAEP
{
/// <summary>
/// Summary description for CodedUITest1
/// </summary>
[CodedUITest]
public class CodedUITest1
{
public CodedUITest1()
{
}
[TestInitialize]
public void InitializationForTest()
{
this.UIMap.AppLaunch();
}
[TestMethod]
public void MainGUIMethod()
{
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
// For more information on generated code, see http://go.microsoft.com/fwlink/?LinkId=179463
this.UIMap.AssertMethod1();
this.UIMap.RestoreDefaults();
this.UIMap.AssertMethod1();
}
[TestMethod]
public void AdvanceSettignsWindowMethod()
{
AdvanceSettings advanceSettings = new AdvanceSettings();
advanceSettings.MoreSettingsReopenedAfterCancel();
this.UIMap.AssertVerificationAfterCancel();
advanceSettings.MoreSettingsReopenedAfterOK();
this.UIMap.AssertVerificationAfterOK();
}
#region Additional test attributes
// You can use the following additional attributes as you write your tests:
////Use TestInitialize to run code before running each test
//[TestInitialize()]
//public void MyTestInitialize()
//{
// // To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
// // For more information on generated code, see http://go.microsoft.com/fwlink/?LinkId=179463
//}
////Use TestCleanup to run code after each test has run
//[TestCleanup()]
//public void MyTestCleanup()
//{
// // To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
// // For more information on generated code, see http://go.microsoft.com/fwlink/?LinkId=179463
//}
#endregion
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
private TestContext testContextInstance;
public UIMap UIMap
{
get
{
if ((this.map == null))
{
this.map = new UIMap();
}
return this.map;
}
}
private UIMap map;
}
}
You cann't use multiple UI Maps with the from existing recording feature. this feature always generates code in a map called UIMap. I've explained a bit about these limitation in a blog post i did about integrating specflow with Coded Ui tests
http://rburnham.wordpress.com/2011/05/30/record-your-coded-ui-test-methods/
If you want to use Multiple UIMaps for better maintainability you have to use this method
Record each action individually by right clicking the UIMap and selecting Coded UI Test Builder.
Manually wire up the test to the actions by creating a blank Coded UI Test, update the UIMap it references and then in the test methods call the required actions to perform the test.
Its a limitation that makes what is good about the MTM integration pointless.
Having multiple UIMaps speeds the test execution. Additionally this makes editions, assertions, properties and settings a lot easier.
To create tests for the second UIMap you just right click on it and press "Edit With Coded UI Test Builder"
Regarding the But I can not generate code from existing recording. Why is that? I have no clue - what do you mean by can not?