├── .gitattributes
├── .gitignore
├── AppToNotifyUsers.sln
├── CONTRIBUTING.md
├── LICENSE
├── WorkerHost
├── App.config
├── ConfigurationLoader.cs
├── EventHubReader.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── WorkerHost.csproj
└── packages.config
├── WorkerRole
├── ServiceConfiguration.Cloud.cscfg
├── ServiceConfiguration.Local.cscfg
├── ServiceDefinition.csdef
├── WorkerHostContent
│ └── diagnostics.wadcfgx
└── WorkerRole.ccproj
├── contribute.md
├── event-hubs-erp-alert.png
├── event-hubs-sensor-alert.png
├── event-hubs-sensors-notify-users.md
└── readme.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | # Prevent from further automatic changes
5 | * text=binary
6 |
7 | ###############################################################################
8 | # We assume following configuration
9 | # Some sh files and other could be changed from Windows too
10 | ###############################################################################
11 | #* text=auto
12 | #*.sln text eol=crlf
13 | #*.csproj text eol=crlf
14 | #*.cs text eol=crlf
15 | #*.cpp text eol=crlf
16 | #*.h text eol=crlf
17 | #*.config text eol=crlf
18 | #*.sql text eol=crlf
19 | #*.asax text eol=crlf
20 | #*.css text eol=crlf
21 | #*.js text eol=crlf
22 | #*.xsd text eol=crlf
23 | #
24 | #*.wxs text eol=crlf
25 | #*.wixproj text eol=crlf
26 | #
27 | #*.cmd text eol=crlf
28 | #
29 | #*.ino text eol=lf
30 | #*.py text eol=lf
31 | #*.sh text eol=lf
32 | #
33 | ###############################################################################
34 |
35 | ###############################################################################
36 | # Set default behavior for command prompt diff.
37 | #
38 | # This is need for earlier builds of msysgit that does not have it on by
39 | # default for csharp files.
40 | # Note: This is only used by command line
41 | ###############################################################################
42 | #*.cs diff=csharp
43 |
44 | ###############################################################################
45 | # Set the merge driver for project and solution files
46 | #
47 | # Merging from the command prompt will add diff markers to the files if there
48 | # are conflicts (Merging from VS is not affected by the settings below, in VS
49 | # the diff markers are never inserted). Diff markers may cause the following
50 | # file extensions to fail to load in VS. An alternative would be to treat
51 | # these files as binary and thus will always conflict and require user
52 | # intervention with every merge. To do so, just uncomment the entries below
53 | ###############################################################################
54 | #*.sln merge=binary
55 | #*.csproj merge=binary
56 | #*.vbproj merge=binary
57 | #*.vcxproj merge=binary
58 | #*.vcproj merge=binary
59 | #*.dbproj merge=binary
60 | #*.fsproj merge=binary
61 | #*.lsproj merge=binary
62 | #*.wixproj merge=binary
63 | #*.modelproj merge=binary
64 | #*.sqlproj merge=binary
65 | #*.wwaproj merge=binary
66 |
67 | ###############################################################################
68 | # behavior for image files
69 | #
70 | # image files are treated as binary by default.
71 | ###############################################################################
72 | #*.jpg binary
73 | #*.png binary
74 | #*.gif binary
75 |
76 | ###############################################################################
77 | # diff behavior for common document formats
78 | #
79 | # Convert binary document formats to text before diffing them. This feature
80 | # is only available from the command line. Turn it on by uncommenting the
81 | # entries below.
82 | ###############################################################################
83 | #*.doc diff=astextplain
84 | #*.DOC diff=astextplain
85 | #*.docx diff=astextplain
86 | #*.DOCX diff=astextplain
87 | #*.dot diff=astextplain
88 | #*.DOT diff=astextplain
89 | #*.pdf diff=astextplain
90 | #*.PDF diff=astextplain
91 | #*.rtf diff=astextplain
92 | #*.RTF diff=astextplain
93 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 | AppToNotifyUsers.sln.ide/
11 |
12 | # User-specific files
13 | *.suo
14 | *.user
15 | *.sln.docstates
16 |
17 | # Build results
18 | [Dd]ebug/
19 | [Rr]elease/
20 | x64/
21 | *_i.c
22 | *_p.c
23 | *.ilk
24 | *.meta
25 | *.obj
26 | *.pch
27 | *.pdb
28 | *.pgc
29 | *.pgd
30 | *.rsp
31 | *.sbr
32 | *.tlb
33 | *.tli
34 | *.tlh
35 | *.tmp
36 | *.log
37 | *.vspscc
38 | *.vssscc
39 | .builds
40 |
41 | # Visual C++ cache files
42 | ipch/
43 | *.aps
44 | *.ncb
45 | *.opensdf
46 | *.sdf
47 |
48 | # Visual Studio profiler
49 | *.psess
50 | *.vsp
51 | *.vspx
52 |
53 | # Guidance Automation Toolkit
54 | *.gpState
55 |
56 | # ReSharper is a .NET coding add-in
57 | _ReSharper*
58 |
59 | # NCrunch
60 | *.ncrunch*
61 | .*crunch*.local.xml
62 |
63 | # Installshield output folder
64 | [Ee]xpress
65 |
66 | # DocProject is a documentation generator add-in
67 | DocProject/buildhelp/
68 | DocProject/Help/*.HxT
69 | DocProject/Help/*.HxC
70 | DocProject/Help/*.hhc
71 | DocProject/Help/*.hhk
72 | DocProject/Help/*.hhp
73 | DocProject/Help/Html2
74 | DocProject/Help/html
75 |
76 | # Click-Once directory
77 | publish
78 |
79 | # Publish Web Output
80 | *.Publish.xml
81 |
82 | # NuGet Packages Directory
83 | packages
84 |
85 | # Windows Azure Build Output
86 | csx
87 | *.build.csdef
88 |
89 | # Windows Store app package directory
90 | AppPackages/
91 |
92 | # Others
93 | [Bb]in
94 | [Oo]bj
95 | sql
96 | TestResults
97 | [Tt]est[Rr]esult*
98 | *.Cache
99 | ClientBin
100 | [Ss]tyle[Cc]op.*
101 | ~$*
102 | *.dbmdl
103 | Generated_Code #added for RIA/Silverlight projects
104 |
105 | # Backup & report files from converting an old project file to a newer
106 | # Visual Studio version. Backup files are not needed, because we have git ;-)
107 | _UpgradeReport_Files/
108 | Backup*/
109 | UpgradeLog*.XML
110 |
111 | # NuGet Packages
112 | *.nupkg
113 | .nuget
114 |
115 | #Thumbs.db
116 | Thumbs.db
--------------------------------------------------------------------------------
/AppToNotifyUsers.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.40629.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkerHost", "WorkerHost\WorkerHost.csproj", "{25079398-1602-45EE-837C-D4195A1FBC27}"
7 | EndProject
8 | Project("{CC5FD16D-436D-48AD-A40C-5A424C6E3E79}") = "WorkerRole", "WorkerRole\WorkerRole.ccproj", "{73173D11-AA67-4089-91D5-BBE0BD4C5444}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {25079398-1602-45EE-837C-D4195A1FBC27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {25079398-1602-45EE-837C-D4195A1FBC27}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {25079398-1602-45EE-837C-D4195A1FBC27}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {25079398-1602-45EE-837C-D4195A1FBC27}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {73173D11-AA67-4089-91D5-BBE0BD4C5444}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {73173D11-AA67-4089-91D5-BBE0BD4C5444}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {73173D11-AA67-4089-91D5-BBE0BD4C5444}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {73173D11-AA67-4089-91D5-BBE0BD4C5444}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Azure samples
2 |
3 | Thank you for your interest in contributing to Azure samples!
4 |
5 | ## Ways to contribute
6 |
7 | You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways:
8 |
9 | - Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/event-hubs-dotnet-user-notifications/) whether it was helpful or not.
10 | - Submit issues through [issue tracker](https://github.com/Azure-Samples/event-hubs-dotnet-user-notifications/issues) on GitHub. We are actively monitoring the issues and improving our samples.
11 | - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Microsoft Corporation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/WorkerHost/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
32 |
33 |
34 |
35 |
36 |
37 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/WorkerHost/ConfigurationLoader.cs:
--------------------------------------------------------------------------------
1 | // ---------------------------------------------------------------------------------
2 | // Copyright (c) Microsoft Corporation, Inc. All rights reserved.
3 | //
4 | // The MIT License (MIT)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | // ---------------------------------------------------------------------------------
24 | using System.Collections.Generic;
25 | using System.Configuration;
26 |
27 |
28 | namespace WorkerHost
29 | {
30 | public class AppConfiguration
31 | {
32 | public string DeviceSBConnectionString;
33 | public string DeviceEHName;
34 |
35 |
36 | public string NotificationService;
37 | public string EmailServiceUserName;
38 | public string EmailServicePassword;
39 |
40 | public string SmtpHost;
41 | public bool SmtpEnableSSL;
42 |
43 | public string MessageFromAddress;
44 | public string MessageFromName;
45 | public string MessageSubject;
46 | public string ConsumerGroupPrefix;
47 |
48 | public IList SendToList;
49 | }
50 |
51 | public class SendToConfigSection : ConfigurationSection
52 | {
53 | [ConfigurationProperty("", IsRequired = true, IsDefaultCollection = true)]
54 | public SendToConfigInstanceCollection Instances
55 | {
56 | get { return (SendToConfigInstanceCollection)this[""]; }
57 | set { this[""] = value; }
58 | }
59 | }
60 |
61 | public class SendToConfigInstanceCollection : ConfigurationElementCollection
62 | {
63 | protected override ConfigurationElement CreateNewElement()
64 | {
65 | return new SendToConfigInstanceElement();
66 | }
67 |
68 | protected override object GetElementKey(ConfigurationElement element)
69 | {
70 | return ((SendToConfigInstanceElement)element).Address;
71 | }
72 | }
73 |
74 | public class SendToConfigInstanceElement : ConfigurationElement
75 | {
76 | [ConfigurationProperty("address", IsKey = true, IsRequired = true)]
77 | public string Address
78 | {
79 | get
80 | {
81 | return (string)base["address"];
82 | }
83 | }
84 | }
85 |
86 | internal class SendFromConfigSection : ConfigurationSection
87 | {
88 | [ConfigurationProperty("address", DefaultValue = "address", IsRequired = true)]
89 | public string Address
90 | {
91 | get
92 | {
93 | return (string)this["address"];
94 | }
95 | set
96 | {
97 | this["address"] = value;
98 | }
99 | }
100 |
101 | [ConfigurationProperty("displayName", DefaultValue = "displayName", IsRequired = true)]
102 | public string DisplayName
103 | {
104 | get
105 | {
106 | return (string)this["displayName"];
107 | }
108 | set
109 | {
110 | this["displayName"] = value;
111 | }
112 | }
113 |
114 | [ConfigurationProperty("subject", DefaultValue = "subject", IsRequired = true)]
115 | public string Subject
116 | {
117 | get
118 | {
119 | return (string)this["subject"];
120 | }
121 | set
122 | {
123 | this["subject"] = value;
124 | }
125 | }
126 | }
127 |
128 | public static class ConfigurationLoader
129 | {
130 | public static IList GetSendToList()
131 | {
132 | var addresses = new List();
133 |
134 | SendToConfigSection config = ConfigurationManager.GetSection("sendToList") as SendToConfigSection;
135 |
136 | if (config != null)
137 | {
138 | foreach (SendToConfigInstanceElement e in config.Instances)
139 | {
140 | addresses.Add(e.Address);
141 | }
142 | }
143 |
144 | return addresses;
145 | }
146 |
147 | public static AppConfiguration GetConfig()
148 | {
149 | SendFromConfigSection sendFromSection = (ConfigurationManager.GetSection("sendFrom") as SendFromConfigSection);
150 |
151 | if (sendFromSection == null)
152 | {
153 | return null;
154 | }
155 |
156 | AppConfiguration config = new AppConfiguration
157 | {
158 | DeviceSBConnectionString =
159 | ConfigurationManager.AppSettings.Get("Microsoft.ServiceBus.ServiceBusConnectionString"),
160 | DeviceEHName = ConfigurationManager.AppSettings.Get("Microsoft.ServiceBus.EventHubToMonitor"),
161 | NotificationService = ConfigurationManager.AppSettings.Get("NotificationService"),
162 | EmailServiceUserName = ConfigurationManager.AppSettings.Get("SenderUserName"),
163 | EmailServicePassword = ConfigurationManager.AppSettings.Get("SenderPassword"),
164 | SmtpHost = ConfigurationManager.AppSettings.Get("SmtpHost"),
165 | SmtpEnableSSL = ConfigurationManager.AppSettings.Get("SmtpEnableSSL").ToLowerInvariant() == "true",
166 |
167 | MessageFromAddress = sendFromSection.Address,
168 | MessageFromName = sendFromSection.DisplayName,
169 | MessageSubject = sendFromSection.Subject,
170 |
171 | SendToList = ConfigurationLoader.GetSendToList(),
172 | ConsumerGroupPrefix = ConfigurationManager.AppSettings.Get("ConsumerGroupPrefix"),
173 | };
174 |
175 | return config;
176 | }
177 | }
178 |
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/WorkerHost/EventHubReader.cs:
--------------------------------------------------------------------------------
1 | // ---------------------------------------------------------------------------------
2 | // Copyright (c) Microsoft Corporation, Inc. All rights reserved.
3 | //
4 | // The MIT License (MIT)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | // ---------------------------------------------------------------------------------
24 |
25 | #define DEBUG_LOG
26 |
27 | using System;
28 | using System.Collections.Generic;
29 | using System.Diagnostics;
30 | using System.Linq;
31 | using System.Text;
32 | using System.Threading;
33 | using System.Threading.Tasks;
34 | using Microsoft.ServiceBus;
35 | using Microsoft.ServiceBus.Messaging;
36 | using Newtonsoft.Json;
37 |
38 | namespace WorkerHost
39 | {
40 | public class EventHubReader
41 | {
42 | private EventHubReceiver[] _receivers = null;
43 | private string _consumerGroupPrefix;
44 |
45 | private Task[] _tasks = null;
46 | private Action _onMessage;
47 |
48 | internal ManualResetEvent FailureEvent = new ManualResetEvent(false);
49 |
50 | public EventHubReader(string consumerGroupPrefix, Action onMessage)
51 | {
52 | _consumerGroupPrefix = consumerGroupPrefix;
53 | _onMessage = onMessage;
54 | }
55 |
56 | public void Close()
57 | {
58 | if (_receivers != null)
59 | {
60 | foreach (var r in _receivers)
61 | {
62 | r.CloseAsync();
63 | }
64 | }
65 | }
66 |
67 | public void Run(string connectionString, string hubName, string measureNameFilter)
68 | {
69 | NamespaceManager nsmgr = NamespaceManager.CreateFromConnectionString(connectionString);
70 | EventHubDescription desc = nsmgr.GetEventHub(hubName);
71 |
72 | //we use already defined consumerGroup name to not reach limit on CG count
73 | string consumerGroupName = _consumerGroupPrefix;
74 | ConsumerGroupDescription consumerGroupDesc = nsmgr.CreateConsumerGroupIfNotExists(new ConsumerGroupDescription(hubName, consumerGroupName));
75 |
76 | EventHubClient client = EventHubClient.CreateFromConnectionString(connectionString, hubName);
77 |
78 | int numPartitions = desc.PartitionCount;
79 | _receivers = new EventHubReceiver[numPartitions];
80 |
81 | _tasks = new Task[numPartitions];
82 |
83 | for (int iPart = 0; iPart < desc.PartitionCount; iPart++)
84 | {
85 | EventHubReceiver receiver = client.GetConsumerGroup(consumerGroupName).CreateReceiver(
86 | desc.PartitionIds[iPart], DateTime.UtcNow - TimeSpan.FromMinutes(2));
87 | _receivers[iPart] = receiver;
88 |
89 | int part = iPart;
90 | Task.Factory.StartNew((state) =>
91 | {
92 | try
93 | {
94 | while (true)
95 | {
96 | var messages = _receivers[part].Receive(1000, TimeSpan.FromSeconds(1));
97 | Process(messages);
98 | }
99 | }
100 | catch (Exception ex)
101 | {
102 | //FailureEvent.Set();
103 | Trace.TraceError("Ignored invalid event data: {0}");
104 | }
105 | }, iPart);
106 | }
107 | }
108 |
109 | void Process(IEnumerable batch)
110 | {
111 | UTF8Encoding enc = new UTF8Encoding();
112 | foreach (EventData e in batch)
113 | {
114 | string body = enc.GetString(e.GetBytes());
115 | string[] lines = body.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
116 |
117 | foreach (var line in lines)
118 | {
119 | try
120 | {
121 | _onMessage(line);
122 | }
123 | catch (Exception)
124 | {
125 | #if DEBUG_LOG
126 | Trace.TraceError("Ignored invalid event data: {0}", line);
127 | #endif
128 | }
129 | }
130 | }
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/WorkerHost/Program.cs:
--------------------------------------------------------------------------------
1 | // ---------------------------------------------------------------------------------
2 | // Copyright (c) Microsoft Corporation, Inc. All rights reserved.
3 | //
4 | // The MIT License (MIT)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | // ---------------------------------------------------------------------------------
24 | //#define DEBUG_LOG
25 | using System;
26 | using System.Collections.Generic;
27 | using System.Configuration;
28 | using System.Diagnostics;
29 | using System.Linq;
30 | using System.Net;
31 | using System.Net.Mail;
32 | using System.Threading;
33 | using Microsoft.WindowsAzure.ServiceRuntime;
34 | using SendGrid;
35 | using Twilio;
36 |
37 | namespace WorkerHost
38 | {
39 | public class WorkerHost : RoleEntryPoint
40 | {
41 | private static EventHubReader _EventHubReader;
42 | private static Timer _Timer;
43 |
44 | private static object _SenderLock = new object();
45 | private static Web _SendGridTransportWeb;
46 | private static SmtpClient _SmtpClient;
47 | private static TwilioRestClient _TwilioRestClient;
48 |
49 | private static MailAddress _FromAddress;
50 | private static MailAddress[] _ToAddress;
51 |
52 | private static AppConfiguration _Config;
53 |
54 | private static NotificationServiceType _NotificationService;
55 | enum NotificationServiceType
56 | {
57 | Smtp = 1,
58 | SendGridWeb = 2,
59 | Twilio = 3,
60 | TwilioCall = 4
61 | }
62 |
63 | static void Main()
64 | {
65 | StartHost("L0cal");
66 | }
67 |
68 | public override void Run()
69 | {
70 | StartHost("R0le");
71 | }
72 |
73 | private static void StartHost(string consumerGroupSuffix)
74 | {
75 | Trace.WriteLine("Starting Worker...");
76 | #if DEBUG_LOG
77 | RoleEnvironment.TraceSource.TraceInformation("Starting Worker...");
78 | #endif
79 |
80 | _Config = ConfigurationLoader.GetConfig();
81 | if (_Config == null)
82 | {
83 | return;
84 | }
85 | _Config.ConsumerGroupPrefix += consumerGroupSuffix;
86 |
87 | _NotificationService =
88 | (NotificationServiceType)Enum.Parse(typeof(NotificationServiceType), _Config.NotificationService);
89 |
90 | var credentials = new NetworkCredential(_Config.EmailServiceUserName, _Config.EmailServicePassword);
91 |
92 | PrepareMailAddressInstances();
93 |
94 | switch (_NotificationService)
95 | {
96 | case NotificationServiceType.Smtp:
97 | {
98 | _SmtpClient = new SmtpClient
99 | {
100 | Port = _Config.SmtpEnableSSL ? 587 : 25,
101 | DeliveryMethod = SmtpDeliveryMethod.Network,
102 | UseDefaultCredentials = false,
103 | EnableSsl = false,
104 | Host = _Config.SmtpHost,
105 | Credentials = credentials
106 | };
107 | }
108 | break;
109 | case NotificationServiceType.SendGridWeb:
110 | {
111 | _SendGridTransportWeb = new Web(credentials);
112 | }
113 | break;
114 | case NotificationServiceType.Twilio:
115 | case NotificationServiceType.TwilioCall:
116 | {
117 | string ACCOUNT_SID = _Config.EmailServiceUserName;
118 | string AUTH_TOKEN = _Config.EmailServicePassword;
119 |
120 | _TwilioRestClient = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
121 | }
122 | break;
123 | }
124 |
125 | _EventHubReader = new EventHubReader(_Config.ConsumerGroupPrefix, OnMessage);
126 |
127 | Process();
128 | }
129 |
130 | private static void PrepareMailAddressInstances()
131 | {
132 | try
133 | {
134 | _FromAddress = new MailAddress(_Config.MessageFromAddress, _Config.MessageFromName);
135 | }
136 | catch (Exception)
137 | {
138 | //incorrect mail address in config, maybe a phone number
139 | }
140 |
141 | IList mailAddressList = new List();
142 |
143 | foreach (var sendTo in _Config.SendToList)
144 | {
145 | try
146 | {
147 | mailAddressList.Add(new MailAddress(sendTo));
148 | }
149 | catch (Exception)
150 | {
151 | //incorrect mail address in config, maybe a phone number
152 | }
153 | }
154 |
155 | _ToAddress = mailAddressList.ToArray();
156 | }
157 |
158 | public static void Process()
159 | {
160 | _EventHubReader.Run(_Config.DeviceSBConnectionString, _Config.DeviceEHName, string.Empty);
161 | _EventHubReader.FailureEvent.WaitOne();
162 | }
163 |
164 | private static void OnMessage(string serializedData)
165 | {
166 | lock (_SenderLock)
167 | {
168 | try
169 | {
170 | if (!_Config.SendToList.Any()) return;
171 |
172 | string messageBody = "Message Received: \n" + serializedData;
173 |
174 | if (_SmtpClient != null)
175 | {
176 | foreach (var mailTo in _ToAddress)
177 | {
178 | try
179 | {
180 | MailMessage myMessage = new MailMessage(_FromAddress, mailTo)
181 | {
182 | Subject = _Config.MessageSubject,
183 | Body = messageBody
184 | };
185 |
186 | _SmtpClient.Send(myMessage);
187 | }
188 | catch (Exception)
189 | {
190 | }
191 | }
192 | }
193 |
194 | if (_SendGridTransportWeb != null)
195 | {
196 | SendGridMessage myMessage = new SendGridMessage(
197 | _FromAddress,
198 | _ToAddress,
199 | _Config.MessageSubject,
200 | string.Empty,
201 | messageBody
202 | );
203 |
204 | _SendGridTransportWeb.DeliverAsync(myMessage).Wait();
205 | }
206 |
207 | if (_TwilioRestClient != null)
208 | {
209 |
210 | switch (_NotificationService)
211 | {
212 | case NotificationServiceType.Twilio:
213 | {
214 | foreach (var smsTo in _Config.SendToList)
215 | {
216 | try
217 | {
218 | _TwilioRestClient.SendMessage(_Config.MessageFromAddress, smsTo,
219 | messageBody);
220 | }
221 | catch (Exception)
222 | {
223 | }
224 | }
225 | }
226 | break;
227 | case NotificationServiceType.TwilioCall:
228 | {
229 | string callUrl = "http://twimlets.com/message?Message%5B0%5D=" + WebUtility.UrlEncode(_Config.MessageSubject);
230 |
231 | foreach (var callTo in _Config.SendToList)
232 | {
233 | try
234 | {
235 | CallOptions options = new CallOptions
236 | {
237 | From = _Config.MessageFromAddress,
238 | To = callTo,
239 | Url = callUrl
240 | };
241 |
242 | Call call = _TwilioRestClient.InitiateOutboundCall(options);
243 | }
244 | catch (Exception)
245 | {
246 | }
247 | }
248 | }
249 | break;
250 | }
251 | }
252 | }
253 | catch (Exception)
254 | {
255 | Trace.WriteLine("Exception on mail sending...");
256 | }
257 | }
258 | }
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/WorkerHost/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // ---------------------------------------------------------------------------------
2 | // Copyright (c) Microsoft Corporation, Inc. All rights reserved.
3 | //
4 | // The MIT License (MIT)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | // ---------------------------------------------------------------------------------
24 |
25 | using System.Reflection;
26 | using System.Runtime.CompilerServices;
27 | using System.Runtime.InteropServices;
28 |
29 | // General Information about an assembly is controlled through the following
30 | // set of attributes. Change these attribute values to modify the information
31 | // associated with an assembly.
32 | [assembly: AssemblyTitle("WorkerHost")]
33 | [assembly: AssemblyDescription("")]
34 | [assembly: AssemblyConfiguration("")]
35 | [assembly: AssemblyCompany("")]
36 | [assembly: AssemblyProduct("WorkerHost")]
37 | [assembly: AssemblyCopyright("Copyright © 2014")]
38 | [assembly: AssemblyTrademark("")]
39 | [assembly: AssemblyCulture("")]
40 |
41 | // Setting ComVisible to false makes the types in this assembly not visible
42 | // to COM components. If you need to access a type in this assembly from
43 | // COM, set the ComVisible attribute to true on that type.
44 | [assembly: ComVisible(false)]
45 |
46 | // The following GUID is for the ID of the typelib if this project is exposed to COM
47 | [assembly: Guid("76fab21f-d875-451d-abf7-e8c352fc7a9f")]
48 |
49 | // Version information for an assembly consists of the following four values:
50 | //
51 | // Major Version
52 | // Minor Version
53 | // Build Number
54 | // Revision
55 | //
56 | // You can specify all the values or you can default the Build and Revision Numbers
57 | // by using the '*' as shown below:
58 | // [assembly: AssemblyVersion("1.0.*")]
59 | [assembly: AssemblyVersion("1.0.0.0")]
60 | [assembly: AssemblyFileVersion("1.0.0.0")]
61 |
--------------------------------------------------------------------------------
/WorkerHost/WorkerHost.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {25079398-1602-45EE-837C-D4195A1FBC27}
8 | Exe
9 | Properties
10 | WorkerHost
11 | WorkerHost
12 | v4.5
13 | 512
14 | false
15 | Worker
16 | publish\
17 | true
18 | Disk
19 | false
20 | Foreground
21 | 7
22 | Days
23 | false
24 | false
25 | true
26 | 1
27 | 1.0.0.%2a
28 | false
29 | true
30 | true
31 |
32 |
33 | AnyCPU
34 | true
35 | full
36 | false
37 | bin\Debug\
38 | DEBUG;TRACE
39 | prompt
40 | 4
41 |
42 |
43 | AnyCPU
44 | pdbonly
45 | true
46 | bin\Release\
47 | TRACE
48 | prompt
49 | 4
50 |
51 |
52 | 95CCA3EE94BEF7B07D71337320FD2BBC359DC7C6
53 |
54 |
55 | WorkerHost_TemporaryKey.pfx
56 |
57 |
58 | true
59 |
60 |
61 | false
62 |
63 |
64 |
65 | ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll
66 |
67 |
68 | ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll
69 |
70 |
71 | ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll
72 |
73 |
74 | ..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll
75 | True
76 |
77 |
78 | ..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll
79 | True
80 |
81 |
82 | ..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll
83 | True
84 |
85 |
86 | ..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll
87 | True
88 |
89 |
90 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.1.203031538-alpha\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
91 |
92 |
93 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.1.203031538-alpha\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll
94 |
95 |
96 | False
97 | ..\packages\WindowsAzure.ServiceBus.2.6.4\lib\net40-full\Microsoft.ServiceBus.dll
98 |
99 |
100 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll
101 |
102 |
103 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll
104 |
105 |
106 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll
107 |
108 |
109 | ..\packages\Microsoft.WindowsAzure.Common.1.4.1\lib\net45\Microsoft.WindowsAzure.Common.dll
110 |
111 |
112 | ..\packages\Microsoft.WindowsAzure.Common.1.4.1\lib\net45\Microsoft.WindowsAzure.Common.NetFramework.dll
113 |
114 |
115 | False
116 | ..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.1.0\lib\net40\Microsoft.WindowsAzure.Configuration.dll
117 |
118 |
119 | True
120 |
121 |
122 | ..\packages\Microsoft.WindowsAzure.Management.ServiceBus.0.17.1-preview\lib\net40\Microsoft.WindowsAzure.Management.ServiceBus.dll
123 |
124 |
125 | False
126 |
127 |
128 | ..\packages\WindowsAzure.Storage.5.0.2\lib\net40\Microsoft.WindowsAzure.Storage.dll
129 | True
130 |
131 |
132 | False
133 | ..\packages\Newtonsoft.Json.7.0.1-beta1\lib\net45\Newtonsoft.Json.dll
134 |
135 |
136 | ..\packages\RestSharp.105.2.2\lib\net45\RestSharp.dll
137 | True
138 |
139 |
140 | ..\packages\SendGrid.SmtpApi.1.3.1\lib\net40\SendGrid.SmtpApi.dll
141 | True
142 |
143 |
144 | ..\packages\Sendgrid.6.1.0\lib\SendGridMail.dll
145 | True
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll
157 |
158 |
159 | ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll
160 |
161 |
162 |
163 |
164 |
165 | ..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll
166 | True
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | ..\packages\Twilio.4.4.0\lib\3.5\Twilio.Api.dll
175 | True
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | Designer
187 |
188 |
189 |
190 |
191 |
192 | False
193 | Microsoft .NET Framework 4.5 %28x86 and x64%29
194 | true
195 |
196 |
197 | False
198 | .NET Framework 3.5 SP1 Client Profile
199 | false
200 |
201 |
202 | False
203 | .NET Framework 3.5 SP1
204 | false
205 |
206 |
207 |
208 |
215 |
--------------------------------------------------------------------------------
/WorkerHost/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/WorkerRole/ServiceConfiguration.Cloud.cscfg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/WorkerRole/ServiceConfiguration.Local.cscfg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/WorkerRole/ServiceDefinition.csdef:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/WorkerRole/WorkerHostContent/diagnostics.wadcfgx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | false
39 |
--------------------------------------------------------------------------------
/WorkerRole/WorkerRole.ccproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.7
8 | 73173d11-aa67-4089-91d5-bbe0bd4c5444
9 | Library
10 | Properties
11 | WorkerRole
12 | WorkerRole
13 | True
14 | WorkerRole
15 | False
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | WorkerHost
43 | {25079398-1602-45ee-837c-d4195a1fbc27}
44 | True
45 | Worker
46 | WorkerHost
47 | True
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | 10.0
60 | $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\2.7\
61 |
62 |
63 |
--------------------------------------------------------------------------------
/contribute.md:
--------------------------------------------------------------------------------
1 | # Contributing to Azure samples #
2 |
3 | Thank you for your interest in contributing to Azure samples!
4 |
5 | ## Ways to contribute
6 |
7 | You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways:
8 |
9 | - Submit feedback on [this sample page](https://github.com/Azure-Samples/event-hubs-dotnet-user-notifications) whether it was helpful or not.
10 | - Submit issues through [issue tracker](https://github.com/Azure-Samples/event-hubs-dotnet-user-notifications/issues) on GitHub. We are actively monitoring the issues and improving our samples.
11 | - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request.
12 |
--------------------------------------------------------------------------------
/event-hubs-erp-alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/event-hubs-dotnet-user-notifications/e132a8f6b1139c0df5168bf04311ff04e14bf356/event-hubs-erp-alert.png
--------------------------------------------------------------------------------
/event-hubs-sensor-alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/event-hubs-dotnet-user-notifications/e132a8f6b1139c0df5168bf04311ff04e14bf356/event-hubs-sensor-alert.png
--------------------------------------------------------------------------------
/event-hubs-sensors-notify-users.md:
--------------------------------------------------------------------------------
1 | # Notify users of data received from sensors or other systems
2 | Suppose you have an application that monitors data in real time, or produces reports on a schedule. If you look at the website on which those real-time charts or reports are displayed, you might see something that requires action. What if you need to be alerted to those situations, rather than relying on remembering to check the website? Imagine that you have a grow light in a greenhouse, and you need to know immediately if the light goes out. One way to do that would be with a light sensor in the greenhouse, arranging to be sent an email if the light is off.
3 |
4 | ![][1]
5 |
6 | In another scenario, imagine that you run a pet boarding facility, and you must be alerted to low inventory supply levels. For example, you might arrange to be sent a text message from your ERP system if your warehouse inventory of dog food has fallen to a critical level.
7 |
8 | ![][2]
9 |
10 | The problem is how to get critical information when certain conditions are met, not when you get around to checking out a static report. If you are using an [Azure Event Hub][Azure Event Hub] or [Azure IoT Hub][Azure IoT Hub] to receive data from devices or enterprise applications such as [Dynamics AX][Dynamics AX], you have several options for how to process them. You can view them on a website, you can analyze them, you can store them, and you can use them to trigger commands to do something. To do this, you can use powerful tools such as [Azure Websites][Azure Websites], [SQL Azure][SQL Azure], [HDInsight][HDInsight], [Cortana Intelligence Suite][Cortana Intelligence Suite], [IoT Suite][IoT Suite], [Logic Apps][Logic Apps], or [Azure Notification Hubs][Azure Notification Hubs]. But sometimes all you want to do is to send that data to someone with a minimum of overhead. To show you how to do that with just a little bit of code, we’ve provided a new sample, [AppToNotifyUsers][AppToNotifyUsers]. Options included are email (SMTP), SMS, and phone.
11 |
12 | ## Application structure
13 | The application is written in C#, and the readme file in the sample contains all the info you need to modify, build, and publish the application. The following sections provide a high-level overview of what the application does.
14 |
15 | We start with the assumption that you have critical events being pushed to an Azure Event Hub or IoT Hub. Any hub will do, as long as you have access to it and know the connection string.
16 |
17 | If you do not already have an Event Hub or IoT hub, you can easily set up a test bed with an Arduino shield and a Raspberry Pi, following the instructions in the [Connect The Dots](https://github.com/Azure/connectthedots) project. The light sensor on the Arduino shield sends the light levels through the Pi to an [Azure Event Hub][Azure Event Hub] (**ehdevices**), and an [Azure Stream Analytics](https://azure.microsoft.com/services/stream-analytics/) job pushes alerts to a second event hub (**ehalerts**) if the light levels received fall below a certain level.
18 |
19 | When **AppToNotify** starts, it reads a configuration file (App.config) to get the URL and credentials for the Event Hub receiving the alerts. It then spawns a process to continuously monitor that Event Hub for any message that comes through – as long as you have can access the URL for the Event Hub or IoT hub and valid credentials, this Event Hubs reader code will continuously read what's coming in. During startup, the application also reads the URL and credentials for the messaging service (email, SMS, phone) you want to use, and the name/address of the sender and a list of recipients.
20 |
21 | Once the Event Hub monitor detects a message, it triggers a process that sends that message using the method specified in the configuration file. Note that it sends every message it detects. If you set the monitor to point to an Event Hub that receives ten messages per second, the sender will send ten messages per second – ten emails per second, ten SMS messages per second, ten phone calls per second. For that reason, make sure that you monitor an Event Hub that only receives the alerts that need to be sent out, not an Event Hub that receives all the raw data from your sensors or applications.
22 |
23 | ## Applicability
24 | The code in this sample only shows how to monitor Event Hubs and how to call external messaging services in the event that you want to add this functionality to your application. Note that this solution is a DIY, developer-focused example only. It does not address enterprise requirements such as redundancy, fail-over, restart upon failure, etc. For more comprehensive and production solutions, see the following:
25 |
26 | * Using connectors or push notifications using the [Azure Logic Apps](../app-service-logic/app-service-logic-connectors-list.md) service.
27 | * Using [Azure Notification Hubs](https://msdn.microsoft.com/library/azure/jj927170.aspx), as described the blog [Broadcast push notifications to millions of mobile devices using Azure Notification Hubs](http://weblogs.asp.net/scottgu/broadcast-push-notifications-to-millions-of-mobile-devices-using-windows-azure-notification-hubs).
28 |
29 | ## Next steps
30 | It is straightforward to create a simple notification service that sends emails or text messages to recipients, or calls them, to relay data received by an Event Hub or IoT Hub. To deploy the solution to notify users based upon data received by these hubs, visit [AppToNotifyUsers][AppToNotifyUsers].
31 |
32 | For more information about these hubs, see the following articles:
33 |
34 | * [Azure Event Hubs]
35 | * [Azure IoT Hub]
36 | * Get started with an [Event Hubs tutorial].
37 | * A complete [sample application that uses Event Hubs].
38 |
39 | To deploy the solution to notify users based on data received by these hubs, visit:
40 |
41 | * [AppToNotifyUsers][AppToNotifyUsers]
42 |
43 | [Event Hubs tutorial]: event-hubs-csharp-ephcs-getstarted.md
44 | [Azure IoT Hub]: https://azure.microsoft.com/services/iot-hub/
45 | [Azure Event Hubs]: https://azure.microsoft.com/services/event-hubs/
46 | [Azure Event Hub]: https://azure.microsoft.com/services/event-hubs/
47 | [sample application that uses Event Hubs]: https://code.msdn.microsoft.com/Service-Bus-Event-Hub-286fd097
48 | [AppToNotifyUsers]: https://github.com/Azure-Samples/event-hubs-dotnet-user-notifications
49 | [Dynamics AX]: http://www.microsoft.com/dynamics/erp-ax-overview.aspx
50 | [Azure Websites]: https://azure.microsoft.com/services/app-service/web/
51 | [SQL Azure]: https://azure.microsoft.com/services/sql-database/
52 | [HDInsight]: https://azure.microsoft.com/services/hdinsight/
53 | [Cortana Intelligence Suite]: http://www.microsoft.com/server-cloud/cortana-analytics-suite/Overview.aspx?WT.srch=1&WT.mc_ID=SEM_lLFwOJm3&bknode=BlueKai
54 | [IoT Suite]: https://azure.microsoft.com/solutions/iot-suite/
55 | [Logic Apps]: https://azure.microsoft.com/services/app-service/logic/
56 | [Azure Notification Hubs]: https://azure.microsoft.com/services/notification-hubs/
57 | [Azure Stream Analytics]: https://azure.microsoft.com/services/stream-analytics/
58 |
59 | [1]: event-hubs-sensor-alert.png
60 | [2]: event-hubs-erp-alert.png
61 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ---
2 | services: event-hubs, iot-hub, cloud-services, notification-hubs
3 | platforms: dotnet
4 | author: spyrossak
5 | ---
6 |
7 | # Notify users of events received by an event or IoT hub
8 |
9 | For more information about this sample, see the [Notify users of data received from sensors or other systems](https://github.com/Azure-Samples/event-hubs-dotnet-user-notifications/blob/master/event-hubs-sensors-notify-users.md) topic in this repository.
10 |
11 | If you are using Azure Stream Analytics or Azure Machine Learning to generate alerts based upon data coming from your devices, you have various options on how to display those alerts. For example, as in the [Connect The Dots](https://github.com/Azure/connectthedots) project, you could display them on a website, so users could see them in real-time if they are looking at a web page. By contrast, the code here, in the [AppToNotifyUsers](https://github.com/Azure-Samples/event-hubs-dotnet-user-notifications) solution, provides a very basic and stand-alone application for selected users to be notified of alerts. It does so by creating an Azure Cloud Service (worker role) that monitors the assigned event hub and pushes that data to a notification service specified by the administrator. Notification options in the solution include:
12 |
13 | - SMTP
14 | - SMS
15 | - Phone
16 |
17 | The user can easily add alternative notification options (such as Twitter), following the work flow in the current solution. Note that each of these solutions require a subscription to an external service (e.g. an email service if notifying users over email). A different architecture, using Twitter for Notifications is shown in Olivier Bloch's posting [Tweet vibration anomalies detected by Azure IoT services on data from an Intel Edison running Node.js](https://azure.microsoft.com/en-us/documentation/samples/iot-hub-nodejs-intel-edison-vibration-anomaly-detection/).
18 |
19 | Note that this solution is a DIY, developer-focused example only. It does not address enterprise requirements such as redundancy, fail-over, restart upon failure, etc. For more comprehensive and production solutions, check out the following:
20 |
21 | * Using connectors or push notifications from an Azure Notification Hub available in [Logic Apps](https://azure.microsoft.com/en-us/documentation/articles/app-service-logic-connectors-list)
22 | * See this [Notification Hubs Overview](https://msdn.microsoft.com/library/azure/jj927170.aspx) for background on Notification Hubs
23 | * [Broadcast push notifications to millions of mobile devices using Windows Azure Notification Hubs](http://weblogs.asp.net/scottgu/broadcast-push-notifications-to-millions-of-mobile-devices-using-windows-azure-notification-hubs) by Scott Guthrie
24 |
25 |
26 | ## WARNING ##
27 |
28 | This application runs in the cloud, and will push ALL the data your event hub of choice receives to the users you list. The anticipated scenario is that you monitor an event hub that is dedicated to receiving alerts on a sporadic basis (maybe once a day or once a week), in which case your targeted users will get an alert pushed to them once a day or once a week. If, however, you monitor an event hub that is getting data every second then your users will get an alert once a second. Realize that it may take a few minutes to stop a cloud service once it is running, so that your user(s) may get 60 emails a minute until the service is fully shut down if you make the wrong choice - assuming you are at a computer and able to connect to the Azure management portal to stop the service! We strongly suggest you do not set this up and then go away for a two week vacation without testing anticipated scenarios...
29 |
30 |
31 | # Prerequisites #
32 |
33 | In order to configure and deploy the AppToNotifyUsers application you will need to have set up an Event Hub and know the Connection String. The easiest way to do this is to use [AzurePrep](https://github.com/Azure/connectthedots/tree/master/Azure/AzurePrep ) in the Connect The Dots repo, but that is not a prerequisite - set up the Event Hub manually if you like.
34 |
35 | You will also need an account or subscription to the user service of your choice - for example an email service such as your ISP, or a computer-to-SMS or Voice service.
36 |
37 | # Setup Tasks #
38 |
39 | Setting up the application once you have an Event Hub and its Connection String involves the following tasks, which will be described in greater detail below.
40 |
41 | 1. Get and set up a subscription for the notification service of your choice
42 | 2. Clone or copy the project to your machine
43 | 2. Open AppToNotifyUsers.sln solution in Visual Studio
44 | 3. Edit App.config in the Worker Host folder to provide the following
45 | 1. The connection string to your Event Hub
46 | 2. The URL for the web service which you will use to push the data
47 | 3. The credentials you will use for accessing that web service
48 | 4. The information about the sender
49 | 5. The information about the users to be notified
50 | 4. Build the project from the *BUILD* menu (Select Release, not Debug)
51 | 5. Publish the application to your Azure subscription
52 | 6. Generate an alert by doing something to one of your devices, and verify that the alert is making it to your event hub (ehalerts)
53 | 7. Verify that the alert is making it to the targeted user (email, SMS, or phone call received by the listed users).
54 |
55 |
56 | # Editing app.config #
57 |
58 | There are three sections of App.config you will need to change - to specify the Event Hub to monitor, to specify the method by which the messages will be sent, and to specify the sender and recipients of the messages.
59 |
60 | ## Step 1: Specifying the Event Hub to Monitor ##
61 | The code in AppToNotifyUsers creates an Azure Cloud Service (worker role) that monitors an event hub identified by a URL you list a config file, App.config, together with the Shared Key that grants you access. The strings in App.config that needs to be modified are the following:
62 | ```
63 |
64 |
65 | ```
66 | If you deploy the example in the Connect The Dots, that event hub is called ehalerts, and you would replace [Event Hub name] with 'ehalerts', and the ServiceBusConnectionString string with the connection string for it, that you can find in the Azure management portal. It should look something like this:
67 |
68 | ```
69 |
70 |
71 | ```
72 | The EventHubReader module in the code uses this information to get messages from ehalerts, and put it in a queue to be sent by whatever method you specify.
73 |
74 | ## Step 2: Select the outbound messaging service ##
75 | Notification options in the solution are encoded as separate subroutines that are called depending upon entries in the App.Config file. Currently there are three options included in the sample code:
76 |
77 | * SMTP
78 | * SMS
79 | * Phone
80 |
81 | As with the Event Hub, you need to specify in App.Config the service you will be using to push the alerts and the credentials for that service. The keys are as follows:
82 | ```
83 |
84 |
85 |
86 |
87 |
88 | ```
89 | If you want to use email to send your alerts, replace [Service option] with 'SMTP', the SMTPHost with your email server name, and enter the credentials that are allowed to use that service. If you want to use SMS, and have a subscription to a service such as Twilio, replace [Service option] with 'SMS', and so forth. You can add additional or alternative notification options easily, such as using Twitter, following the work flow in the current solution. Note: Each of these solutions require a subscription to an external service (e.g. an email service if notifying users over email).
90 |
91 | To repeat what was said earlier, this solution is strictly a DIY, developer-focused example only. For more comprehensive production-level solutions, please check out the other solutions listed at the beginning of this file.
92 | ## Step 3: Identify the Sender and Recipients of the Messages ##
93 | Once you have specified how messages will be sent, you need to identify from whom, and to whom, they will be sent. If the Notification Service is SMTP, either using an SMTP host to which you have access, or using SendGrid, you would specify an email address in the sendFrom address in App.Config:
94 | ```
95 |
96 | ```
97 | If you are using an SMTP (email) sender, this would be the display name and email alias shown on the From and Subject lines of the email. Note that the sender address you enter will be that shown on the email as received by the recipient. If they are expected to reply, that should be a real email recipient. Furthermore, if you are sending a lot of email to various recipients, make sure that they are ok with getting those emails, so your sender does not get labeled as a spammer!
98 |
99 | If you are using a service like Twilio to send SMS messages, this would be the phone number Twilio assigns to you for the sender of the SMS. Similarly for the recipient list:
100 | ```
101 |
102 |
103 |
104 |
105 | ```
106 |
107 |
108 |
109 | # Publishing the application #
110 | You use Visual Studio to publish and start the application. The steps are as follows:
111 | * In Visual Studio, right-click on 'WorkerRole' in Solution 'AppToNotifyUsers', and select *Publish*.
112 | * In the Publish Azure Application, answer the following questions.
113 | * Name: [pick something unique]
114 | * Region: [pick same region as you used for the Event Hub]
115 | * Database server: no database
116 | * Database password: [leave suggested password]
117 | * Click Publish, and wait until the status bar shows "Completed". At that point the application is running in your subscription, polling the event hub you listed, and pushing everything it receives to the users you listed over the service you picked.
118 |
--------------------------------------------------------------------------------