Why does Azure scm show only one method? - azure

I have this code in my project that I uploaded to Azure Web Job.
class Program {
static void Main(string[] args) {
var host = new JobHost();
host.RunAndBlock();
}
public static async Task AddSomethingAsync([QueueInput("myqueue1")] string _)
{
//....
}
public static async Task UpdateSomethingAsync([QueueInput("myqueue2")] string _)
{
//....
}
}
}
But it shows the first function "AddSomethingAsync" only in azure scm site (https://me.scm.azurewebsites.net/azurejobs/#/jobs/triggered/myjob/runs/201406170707442616)
Is it the known issue or Am I missing something?
Thanks!

Okie. I got it now. I need to go to Functions page to see it. The default shows only the first method.

Related

Blob path name provider for WebJob trigger

I have a following test code that is placed inside a WebJob project. It is triggered after any blob is created (or changed) inside "cBinary/test1/" storage account.
The code works.
public class Triggers
{
public void OnBlobCreated(
[BlobTrigger("cBinary/test1/{name}")] Stream blob,
[Blob("cData/test3/{name}.txt")] out string output)
{
output = DateTime.Now.ToString();
}
}
The question is: how to get rid of ugly hard-coded const string "cBinary/test1/" and ""cData/test3/"?
Hard-coding is one problem, but I need to create and maintain couple of such strings (blob directories) that are created dynamically - depend of supported types. What's more - I need this string value in couple of places, I don't want to duplicate it.
I would like them to be placed in some kind of configuration provider that builds the blob path string depending on some enum, for instance.
How to do it?
You can implement INameResolver to resolve QueueNames and BlobNames dynamically. You can add the logic to resolve the name there. Below is some sample code.
public class BlobNameResolver : INameResolver
{
public string Resolve(string name)
{
if (name == "blobNameKey")
{
//Do whatever you want to do to get the dynamic name
return "the name of the blob container";
}
}
}
And then you need to hook it up in Program.cs
class Program
{
// Please set the following connection strings in app.config for this WebJob to run:
// AzureWebJobsDashboard and AzureWebJobsStorage
static void Main()
{
//Configure JobHost
var storageConnectionString = "your connection string";
//Hook up the NameResolver
var config = new JobHostConfiguration(storageConnectionString) { NameResolver = new BlobNameResolver() };
config.Queues.BatchSize = 32;
//Pass configuration to JobJost
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
Finally in Functions.cs
public class Functions
{
public async Task ProcessBlob([BlobTrigger("%blobNameKey%")] Stream blob)
{
//Do work here
}
}
There's some more information here.
Hope this helps.

Expose webjobs functions to dashboard without azure storage

In this question there's an example on how to use a webjob that can perform some background operations without interacting with azure table storage.
I tried to replicate the code in the answer but it's throwing the following error:
' 'Void ScheduleNotifications()' can't be invoked from Azure WebJobs SDK. Is it missing Azure WebJobs SDK attributes? '
In this link they have a similar error and in one of the answers it says that this was fixed in the 0.4.1-beta release. I'm running the 0.5.0-beta release and I'm experiencing the error.
Here's a copy of my code:
class Program
{
static void Main()
{
var config = new JobHostConfiguration(AzureStorageAccount.ConnectionString);
var host = new JobHost(config);
host.Call(typeof(Program).GetMethod("ScheduleNotifications"));
host.RunAndBlock();
}
[NoAutomaticTrigger]
public static void ScheduleNotifications()
{
//Do work
}
}
I want to know if I'm missing something or is this still a bug in the Webjobs SDK.
Update: Per Victor's answer, the Program class has to be public.
Working code:
public class Program
{
static void Main()
{
var config = new JobHostConfiguration(AzureStorageAccount.ConnectionString);
var host = new JobHost(config);
host.Call(typeof(Program).GetMethod("ScheduleNotifications"));
host.RunAndBlock();
}
[NoAutomaticTrigger]
public static void ScheduleNotifications()
{
//Do work
}
}
Unless you use a custom type locator, a function has to satisfy all conditions below:
it has to be public
it has to be static
it has to be non abstract
it has to be in a non abstract class
it has to be in a public class
Your function doesn't meet the last condition. If you make the class public it will work.
Also, if you use webjobs sdk 0.5.0-beta and you run a program with only the code in your example, you will see a message saying that no functions were found.
Came looking for an answer here, but didn't quite find it in the answer above, though everything he said is true. My problem was that I accidentally changed the inbound property names of a Azure web job so that they DIDN'T match the attributes of the object the function was supposed to catch. Duh!
For the concrete example:
my web job was listening for a queue message based on this class:
public class ProcessFileArgs
{
public ProcessFileArgs();
public string DealId { get; set; }
public ProcessFileType DmsFileType { get; set; }
public string Email { get; set; }
public string Filename { get; set; }
}
But my public static async class in the Functions.cs file contained this as a function definition, where the declared parameters didn't match the names within the queue message class for which it was waiting:
public static async Task LogAndLoadFile(
[QueueTrigger(Queues.SomeQueueName)] ProcessFileArgs processFileArgs,
string dealid,
string emailaddress,
string file,
[Blob("{fileFolder}/{Filename}", FileAccess.Read)] Stream input,
TextWriter log,
CancellationToken cancellationToke)
{
So if you run into this problem, check to make sure the parameter and attribute names match.

Determining application context from OWIN pipeline?

I have an OWIN pipeline using Nancy:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNancy();
}
}
The UseNancy() is actually a call to my own custom extension method defined in this gist: https://gist.github.com/TheFastCat/0b7635d9e5795b44e72e
This code is executed both as an Azure Website or an Azure Cloud Service. Based on the context it is executing within I want to use a particular favicon, loaded as an embedded resource from a separate assembly. I do this by specifying separate NancyBootstrappers (each loading the proper favicon for its context).
Is there a more elegant solution to determining the runtime application that is executing the OWIN pipeline? Currently I check app.Properties["host.AppName"] ; however while the Website's app name matches it's assembly configuration, the CloudService app is the name of the Owin startup assembly.class. (see gist). It's cloogey.
Is there a more elegant/simple solution for specifying a custom favicon within Nancy for each of my web applications than creating separate bootstrappers and doing runtime application context checks?
I solved this problem with the help of others on the https://jabbr.net/#/rooms/owin and https://jabbr.net/#/rooms/nancyfx chat boards
Yes. You can contextually check the OWIN host properties:
if (app.Properties.ContainsKey("System.Net.HttpListener"))
{
// self hosted application context
}
2.) Yes.
namespace ClassLib
{
public class Startup()
{
public Startup(byte[] favIcon) { ... }
public void Configuration(IAppBuilder app) { ... }
}
}
[assembly: OwinStartup(typeof(WebHost.Startup))]
namespace WebHost
{
public class Startup()
{
public voic Configuration(IAppBuilder app)
{
new ClassLib.Startup(webhostFavIcon).Configuration(app);
}
}
}
namespace SelfHost
{
private class Program()
{
public void Main(string[] args)
{
using(WebApp.Start(app => new ClassLib.Startup(selfHostFavIcon).Configuration(app))
{}
}
}
}

Playframework Excel file generation

I've installed excel module in order to generate reports from datas recorded by my application into database.
It works fine : i can create report simply by clicking on a link into my main page and render into excel template.
But i'd rather generate excel file periodically (using a job) and save it into a shared folder, and that without any human action (so not by clicking on a link).
It's like I want to trigger the associated controller to render into my template automatically.
Does anyone got any tips on it for me?
So the problem is you can't pass some parameters into the job, or...?
Using something like this just doesn't work?
#On("0 45 4-23 ? * MON-FRI")
public class ExcelJob extends Job {
public void doJob() {
// generate excel
}
}
I wrote my own Excel generator using JExcel, and I use it for scheduled generation without a problem. It also doesn't require a template, because the report structure is derived from annotations. This is roughly 20 lines of code - you may want to try it for yourself.
This is really rough and lacks good user feedback, but gives you the idea...
Excel generator - not Play-specific in any way
public class ExcelGenerator
{
public void generateReport(Function successCallback,
Function failureCallback)
{
try
{
byte[] report = // generate your report somehow
successCallback.execute(report);
}
catch (Exception e)
{
failureCallback.execute(e.getMessage());
}
}
}
A function interface for callbacks (very basic)
public interface Function
{
public void execute(Object... args);
}
Your Play controller
public class MyController extends Controller
{
public static void index()
{
render();
}
public static void createReport()
{
Function failureCallback = new Function()
{
public void execute(Object... args)
{
flash.error(args[0]);
indxe();
}
};
Function successCallback = new Function()
{
public void execute(Object... args)
{
renderBinary((byte[])args[0]);
}
};
ExcelGenerator excelGenerator = new ExcelGenerator();
excelGenerator.generateReport(successCallback,
failureCallback);
}
}
Finally, re-use the ExcelGenerator from your job
public class MyJob extends Job
{
public void doJob()
{
Function failureCallback = new Function()
{
public void execute(Object... args)
{
Logger.error(args[0]);
}
}
Function successCallback = new Function()
{
public void execute(Object... args)
{
byte[] report = (byte[])args[0];
// write report to disk
}
}
ExcelGenerator excelGenerator = new ExcelGenerator();
excelGenerator.generateReport(successCallback,
failureCallback);
}
}
You'll still need to write your own report generator, or refactor the existing excel module to provide what you need.
So if you want to run and manage several jobs you can do something like this
for (int i = 0; i < 10; i++) {
SendingMessageJob sendingMessageJob = new SendingMessageJob();
promises.add(sendingMessageJob.now());
}
boolean allDone = false;
while (!allDone) {
allDone = true;
for (F.Promise promise : promises) {
if (!promise.isDone()) {
allDone = false;
break;
}
}
}
// when arrive here all jobs have finished their process
You can check the Play documentation, specifically the section on jobs, where you'll see examples on how to create automatically triggered methods. This should solve your issue.
EDIT (update on comment):
You can manually trigger a job, do this:
new MyExcelGeneratorJob().doJob();
Thing is, Play is stateless, so the job should use data from the database. Instead of trying to pass parameters from your request into the Job (won't work) try to store that data in a staging area in the database that the job loads and processes to generate the excel.

Spec fails when run by mspec.exe, but passes when run by TD.NET

I wrote about this topic in another question.
However, I've since refactored my code to get rid of configuration access, thus allowing the specs to pass. Or so I thought. They run fine from within Visual Studio using TestDriven.Net. However, when I run them during rake using the mspec.exe tool, they still fail with a serialization exception. So I've created a completely self-contained example that does basically nothing except setup fake security credentials on the thread. This test passes just fine in TD.Net, but blows up in mspec.exe. Does anybody have any suggestions?
Update: I've discovered a work-around. After researching the issue, it seems the cause is that the assembly containing my principal object is not in the same folder as the mspec.exe. When mspec creates a new AppDomain to run my specs, that new AppDomain has to load the assembly with the principal object in order to deserialize it. That assembly is not in the same folder as the mspec EXE, so it fails. If I copied my assembly into the same folder as mspec, it works fine.
What I still don't understand is why ReSharper and TD.Net can run the test just fine? Do they not use mspec.exe to actually run the tests?
using System;
using System.Security.Principal;
using System.Threading;
using Machine.Specifications;
namespace MSpecTest
{
[Subject(typeof(MyViewModel))]
public class When_security_credentials_are_faked
{
static MyViewModel SUT;
Establish context = SetupFakeSecurityCredentials;
Because of = () =>
SUT = new MyViewModel();
It should_be_initialized = () =>
SUT.Initialized.ShouldBeTrue();
static void SetupFakeSecurityCredentials()
{
Thread.CurrentPrincipal = CreatePrincipal(CreateIdentity());
}
static MyIdentity CreateIdentity()
{
return new MyIdentity(Environment.UserName, "None", true);
}
static MyPrincipal CreatePrincipal(MyIdentity identity)
{
return new MyPrincipal(identity);
}
}
public class MyViewModel
{
public MyViewModel()
{
Initialized = true;
}
public bool Initialized { get; set; }
}
[Serializable]
public class MyPrincipal : IPrincipal
{
private readonly MyIdentity _identity;
public MyPrincipal(MyIdentity identity)
{
_identity = identity;
}
public bool IsInRole(string role)
{
return true;
}
public IIdentity Identity
{
get { return _identity; }
}
}
[Serializable]
public class MyIdentity : IIdentity
{
private readonly string _name;
private readonly string _authenticationType;
private readonly bool _isAuthenticated;
public MyIdentity(string name, string authenticationType, bool isAuthenticated)
{
_name = name;
_isAuthenticated = isAuthenticated;
_authenticationType = authenticationType;
}
public string Name
{
get { return _name; }
}
public string AuthenticationType
{
get { return _authenticationType; }
}
public bool IsAuthenticated
{
get { return _isAuthenticated; }
}
}
}
Dan,
thank you for providing a reproduction.
First off, the console runner works differently than the TestDriven.NET and ReSharper runners. Basically, the console runner has to perform a lot more setup work in that it creates a new AppDomain (plus configuration) for every assembly that is run. This is required to load the .dll.config file for your spec assembly.
Per spec assembly, two AppDomains are created:
The first AppDomain (Console) is created
implicitly when mspec.exe is
executed,
a second AppDomain is created by mspec.exe for the assembly containing the specs (Spec).
Both AppDomains communicate with each other through .NET Remoting: For example, when a spec is executed in the Spec AppDomain, it notifies the Console AppDomain of that fact. When Console receives the notification it acts accordingly by writing the spec information to the console.
This communiciation between Spec and Console is realized transparently through .NET Remoting. One property of .NET Remoting is that some properties of the calling AppDomain (Spec) are automatically included when sending notifications to the target AppDomain (Console). Thread.CurrentPrincipal is such a property. You can read more about that here: http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
The context you provide will run in the Spec AppDomain. You set Thread.CurrentPrincipal in the Because. After Because ran, a notification will be issued to the Console AppDomain. The notification will include your custom MyPrincipal that the receiving Console AppDomain tries to deserialize. It cannot do that since it doesn't know about your spec assembly (as it is not included in its private bin path).
This is why you had to put your spec assembly in the same folder as mspec.exe.
There are two possible workarounds:
Derive MyPrincipal and MyIdentity from MarshalByRefObject so that they can take part in cross-AppDomain communication through a proxy (instead of being serialized)
Set Thread.CurrentPrincipal transiently in the Because
(Text is required for formatting to work -- please ignore)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
ReSharper, for example, handles all the communication work for us. MSpec's ReSharper Runner can hook into the existing infrastructure (that, AFAIK, does not use .NET Remoting).

Resources