Windows Azure Active Directory–Authentifizierung “nur Code” & erste Schritte mit der Graph API

f59fb440-4801-4261-a7db-2d68345523b6-1.png

Bereits mit VS 2012 und dem “Identity Toolkit” konnte man sich seine ASP.NET Applikation recht einfach so konfigurieren, dass der Anwender sich beim Windows Azure Active Directory (WAAD) anmelden kann. Mit VS 2013 ist die Sache natürlich noch eleganter geworden, aber trotzdem bin ich bei diesen Tooling Geschichten skeptisch. In dem Blogpost zeige ich was eigentlich hinter den Kulissen passiert und dass da eigentlich gar keine so große Magie dahinter steckt.

Stop… Windows Azure Active Directory? What?

Wer noch nie was vom Windows Azure AD gehört hat, dem empfehle ich dies hier. In Kürze: WAAD ist im Grunde ein Multimandanten Active Directory in der Cloud. Alllerdings ohne LDAP Zugriff, sondern mit einer REST Schnittstelle und verschiedenen Authentifizierungsverfahren (OAuth, WSFed etc.). Technisch gesehen sind es komplett getrennte Sachen – aber vom Konzept her ist es sehr ähnlich.

Die Toolkits – was machen die denn?

Wenn man mit VS 2013 ein neues ASP.NET Projekt startet wird man gefragt welche Authentifizierungsvariante man haben möchte.

image

Unter “Organizational Accounts” kann man seine WAAD Daten eintragen und das Tool konfiguriert die Anwendung.

Ergebnis davon:

Falls man nicht bereits irgendwo im WAAD-Universum (z.b. bei Office 365) eingeloggt ist, wird man direkt auf die Anmeldeseite umgeleitet:

image

image

Die Entmystifizierung oder: Wir machen das jetzt selbst. Ohne Magic.

Als erstes müssen wir eine Anwendung unter userem Azure AD erstellen. Die App URI sollte der URL entsprechen unter dem die Anwendung im IIS Express gehostet wird. Grundsätzlich ist eine HTTPS Adresse von Vorteil und spätestens wenn die Anwendung für andere Azure AD Tenants öffnen möchte, dann wird HTTPS benötigt.

image

 

image

 

Wichtig für den Demo-Code ist die Reply URL die auf Auth/Callback zeigen muss.

Damit der Demo-Code läuft benötigt man sowohl Daten von dem Azure AD Mandanten als auch von der Azure AD App:

(Achtung – einige dieser Einstellungen sind eigentlich “secret” – ich lösch die Anwendung danach wieder)

   1: private string AzureAdAppClientId;

   2: private string AzureAdAppClientSecret;

   3: private string AzureAdAppUri;

   4: private IssuingAuthority AzureAdAuthroAuthority;

   5:  

   6: public AuthController()

   7: {

   8:     AzureAdAppUri = "http://localhost:47828/";

   9:     AzureAdAppClientId = "515e8337-2a81-421a-bf76-cbc78ff89288";

  10:     AzureAdAppClientSecret = "sYEVBHHMM4kQNv2NOT6x0c55sogupaknnr3gdX9cptg=";

  11:  

  12:     // Fix for ID4175 & WIF10201  http://www.cloudidentity.com/blog/2013/02/08/multitenant-sts-and-token-validation-4/

  13:     AzureAdAuthroAuthority = new IssuingAuthority("WAAD");

  14:     // Issuer = Azure Ad Tenant 

  15:     AzureAdAuthroAuthority.Issuers.Add("https://sts.windows.net/3351acfe-7e1b-4e9b-b587-f34bfa2e128a/");

  16:     AzureAdAuthroAuthority.Thumbprints.Add("3464C5BDD2BE7F2B6112E2F08E9C0024E33D9FE0");

  17:  

  18:     // Thumbprint can be read via this code:

  19:     // ia = ValidatingIssuerNameRegistry.GetIssuingAuthority("https://login.windows.net/TENANTID/FederationMetadata/2007-06/FederationMetadata.xml");

  20:  

  21: }

 

Zum Code: Redirect zum Logn

Der Login wird über einen simplen Redirect gemacht:

   1: public ActionResult Index()

   2:         {

   3:             // Develop Multitenant apps http://msdn.microsoft.com/en-us/library/windowsazure/dn151789.aspx - before "https://login.windows.net/3351acfe-7e1b-4e9b-b587-f34bfa2e128a/";

   4:             string issuer = "https://login.windows.net/common/";

   5:  

   6:             // returnUrl can be passed in wctx parameter with rm=0&id=passive&ru=%2fHome%2fAbout

   7:             var redirectUrl = string.Format(@"{0}wsfed?wa=wsignin1.0&wtrealm={1}", issuer, Url.Encode(AzureAdAppUri));

   8:  

   9:             return Redirect(redirectUrl);

  10:         }

Die RedirectUrl sieht in meinem Beispiel so aus:

https://login.windows.net/common/wsfed?wa=wsignin1.0&wtrealm=http%3a%2f%2flocalhost%3a47828%2f

Wie in den Kommentaren geschrieben kann man auch eine “ReturnUrl” in dem wctx Parameter mit angeben.

Der “Callback”: – Token valdieren & ClaimsPrincipal erstellen

Wenn man sich erfolgreich beim Azure AD angemeldet hat, wird die Callback URL der Anwendung aufgerufen (in meinem Beispiel ist dies auf Auth/Callback im Azure AD so eingestellt). In dem Aufruf kommt ein SAML Token mit:

   1: <t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">

   2:     <t:Lifetime>

   3:         <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-11-10T16:02:31.705Z</wsu:Created>

   4:         <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-11-11T04:02:31.705Z</wsu:Expires>

   5:     </t:Lifetime>

   6:     <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">

   7:         <EndpointReference xmlns="http://www.w3.org/2005/08/addressing">

   8:             <Address>http://localhost:47828/</Address>

   9:         </EndpointReference>

  10:     </wsp:AppliesTo>

  11:     <t:RequestedSecurityToken>

  12:         <Assertion ID="_61ae5e5f-fb9a-482f-9ce8-a34506151e96" IssueInstant="2013-11-10T16:02:32.076Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">

  13:             <Issuer>https://sts.windows.net/3351acfe-7e1b-4e9b-b587-f34bfa2e128a/</Issuer>

  14:             <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">

  15:                 <ds:SignedInfo>

  16:                     <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

  17:                     <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />

  18:                     <ds:Reference URI="#_61ae5e5f-fb9a-482f-9ce8-a34506151e96">

  19:                         <ds:Transforms>

  20:                             <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />

  21:                             <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

  22:                         </ds:Transforms>

  23:                         <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />

  24:                         <ds:DigestValue>a1HBgQ8rbt75g09a3G/Yi1jzTsUk7Lu/jjY84ObXjws=</ds:DigestValue>

  25:                     </ds:Reference>

  26:                 </ds:SignedInfo>

  27:                 <ds:SignatureValue>OxoL6jFz0Kc7V5UWNn3jPaXMuEhE/v0u4o5c0W4kCpKd2op95uxJaGDDbtXSatkdPtJMLCXsZ1bQpdp7EfkdPg4KPGhgeCmMD4PPya5cqyxwp7E0gWENEQ3aknruEMizAaFUqq/HCPgdAguKgE+9grD3QANAJN2+sfjdfx3ukoAIKBbo6gkfRqi5mWePu56Zx9/wqxpyAT+gm1mZukFUaqoo3WaCKhaCv27UotJjUy2DaHMXAMDvulpRTCcF9rwsViM5d0NFxKoZykOvRqirdyi8GNYKh5J16E6+KOKE3aJNZljmJY2Ubbs1EhUTwIkYOoeRz/ZVY+VbqIp66BGd/w==</ds:SignatureValue>

  28:                 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">

  29:                     <X509Data>

  30:                         <X509Certificate>MIIDPjCCAiqgAwIBAgIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTIwNjA3MDcwMDAwWhcNMTQwNjA3MDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArCz8Sn3GGXmikH2MdTeGY1D711EORX/lVXpr+ecGgqfUWF8MPB07XkYuJ54DAuYT318+2XrzMjOtqkT94VkXmxv6dFGhG8YZ8vNMPd4tdj9c0lpvWQdqXtL1TlFRpD/P6UMEigfN0c9oWDg9U7Ilymgei0UXtf1gtcQbc5sSQU0S4vr9YJp2gLFIGK11Iqg4XSGdcI0QWLLkkC6cBukhVnd6BCYbLjTYy3fNs4DzNdemJlxGl8sLexFytBF6YApvSdus3nFXaMCtBGx16HzkK9ne3lobAwL2o79bP4imEGqg+ibvyNmbrwFGnQrBc1jTF9LyQX9q+louxVfHs6ZiVwIDAQABo2IwYDBeBgNVHQEEVzBVgBCxDDsLd8xkfOLKm4Q/SzjtoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAA4IBAQAkJtxxm/ErgySlNk69+1odTMP8Oy6L0H17z7XGG3w4TqvTUSWaxD4hSFJ0e7mHLQLQD7oV/erACXwSZn2pMoZ89MBDjOMQA+e6QzGB7jmSzPTNmQgMLA8fWCfqPrz6zgH+1F1gNp8hJY57kfeVPBiyjuBmlTEBsBlzolY9dd/55qqfQk6cgSeCbHCy/RU/iep0+UsRMlSgPNNmqhj5gmN2AFVCN96zF694LwuPae5CeR2ZcVknexOWHYjFM0MgUSw0ubnGl0h9AJgGyhvNGcjQqu9vd1xkupFgaN+f7P3p3EVN5csBg5H94jEcQZT7EKeTiZ6bTrpDAnrr8tDCy8ng</X509Certificate>

  31:                     </X509Data>

  32:                 </KeyInfo>

  33:             </ds:Signature>

  34:             <Subject>

  35:                 <NameID>K_PsyS1F5XHlmjb-RNh1HccLx7yl_kG828eddsz4JEw</NameID>

  36:                 <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" />

  37:             </Subject>

  38:             <Conditions NotBefore="2013-11-10T16:02:31.705Z" NotOnOrAfter="2013-11-11T04:02:31.705Z">

  39:                 <AudienceRestriction>

  40:                     <Audience>http://localhost:47828/</Audience>

  41:                 </AudienceRestriction>

  42:             </Conditions>

  43:             <AttributeStatement>

  44:                 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">

  45:                     <AttributeValue>R</AttributeValue>

  46:                 </Attribute>

  47:                 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">

  48:                     <AttributeValue>M</AttributeValue>

  49:                 </Attribute>

  50:                 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">

  51:                     <AttributeValue>Admin@codeinsidedev.onmicrosoft.com</AttributeValue>

  52:                 </Attribute>

  53:                 <Attribute Name="http://schemas.microsoft.com/identity/claims/tenantid">

  54:                     <AttributeValue>3351acfe-7e1b-4e9b-b587-f34bfa2e128a</AttributeValue>

  55:                 </Attribute>

  56:                 <Attribute Name="http://schemas.microsoft.com/identity/claims/objectidentifier">

  57:                     <AttributeValue>a1b735e1-4b92-4ff9-bd15-4a915c149ff1</AttributeValue>

  58:                 </Attribute>

  59:                 <Attribute Name="http://schemas.microsoft.com/identity/claims/identityprovider">

  60:                     <AttributeValue>https://sts.windows.net/3351acfe-7e1b-4e9b-b587-f34bfa2e128a/</AttributeValue>

  61:                 </Attribute>

  62:             </AttributeStatement>

  63:             <AuthnStatement AuthnInstant="2013-11-03T16:40:15.000Z">

  64:                 <AuthnContext>

  65:                     <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef>

  66:                 </AuthnContext>

  67:             </AuthnStatement>

  68:         </Assertion>

  69:     </t:RequestedSecurityToken>

  70:     <t:RequestedAttachedReference>

  71:         <SecurityTokenReference d3p1:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns:d3p1="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">

  72:             <KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_61ae5e5f-fb9a-482f-9ce8-a34506151e96</KeyIdentifier>

  73:         </SecurityTokenReference>

  74:     </t:RequestedAttachedReference>

  75:     <t:RequestedUnattachedReference>

  76:         <SecurityTokenReference d3p1:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns:d3p1="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">

  77:             <KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_61ae5e5f-fb9a-482f-9ce8-a34506151e96</KeyIdentifier>

  78:         </SecurityTokenReference>

  79:     </t:RequestedUnattachedReference>

  80:     <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>

  81:     <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>

  82:     <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>

  83: </t:RequestSecurityTokenResponse>

Über diesen Code lässt sich das Token validieren und in ein ClaimsPrincipal verwandeln. Wichtigste Library ist dieses NuGet Package, welches man für die Validierung benötigt.

   1: [ValidateInput(false)]

   2: public async Task<ActionResult> Callback(string wresult, string wa, string wctx)

   3: {

   4:     // http://www.tecsupra.com/blog/system-identitymodel-manually-parsing-the-saml-token/

   5:     var wrappedToken = XDocument.Parse(wresult);

   6:     var requestedSecurityToken = wrappedToken.Root.Descendants("{http://schemas.xmlsoap.org/ws/2005/02/trust}RequestedSecurityToken").First();

   7:     var asssertion = requestedSecurityToken.DescendantNodes().First();

   8:  

   9:     var xmlTextReader = asssertion.CreateReader();

  10:  

  11:     var securityTokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();

  12:  

  13:     // Fix for ID1032 http://blog.fabse.net/2013/01/10/id1032-at-least-one-audienceuri-must-be-specified-2/

  14:     securityTokenHandlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri(AzureAdAppUri));

  15:     securityTokenHandlers.Configuration.CertificateValidationMode = X509CertificateValidationMode.None;

  16:     securityTokenHandlers.Configuration.CertificateValidator = X509CertificateValidator.None;

  17:  

  18:     securityTokenHandlers.Configuration.IssuerNameRegistry = new ValidatingIssuerNameRegistry(AzureAdAuthroAuthority);

  19:  

  20:     SecurityToken token = securityTokenHandlers.ReadToken(xmlTextReader);

  21:  

  22:     var viewModel = new CallbackViewModel();

  23:  

  24:     var claimsIdentity = securityTokenHandlers.ValidateToken(token);

  25:  

  26:     var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

  27:     ....

 

Ergebnis:

image

Erster Schritt mit der Graph API

Nachdem wir uns angemeldet haben, kommt in den Claims auch die TenantId mit. Da unsere Anwendung das Recht besitzt auch lesend auf das Azure AD zuzugreifen wollen wir das doch machen.

Hierfür sind zwei Schritte notwendig:

Wir benötigen als erstes ein AccessToken – dies holen wir mit dem Standard HttpClient, welcher in .NET Framework 4.5 vorhanden ist über den OAuth Endpunkt.

Danach nutzen wir diese NuGet Library – welche allerdings im Grunde nur aus den Samples von Microsoft stammt und nicht mehr aktualisiert wird. Man kann die Abfrage auch über die pure REST Api und den HttpClient machen, aber das war mir an der Stelle zu mühsam. Eine anderen eleganten Wrapper um die REST Api habe ich noch nicht gefunden. Falls es da was gibt wäre ich für einen Tipp dankbar.

   1: ...

   2: var tenantId =

   3:     claimsPrincipal.Claims.Single(x => x.Type == "http://schemas.microsoft.com/identity/claims/tenantid")

   4:                    .Value;

   5:  

   6: var waadRequest = new HttpClient();

   7:  

   8: string postData = "grant_type=client_credentials";

   9: postData += "&resource=" + HttpUtility.UrlEncode("https://graph.windows.net");

  10: postData += "&client_id=" + HttpUtility.UrlEncode(AzureAdAppClientId);

  11: postData += "&client_secret=" + HttpUtility.UrlEncode(AzureAdAppClientSecret);

  12: var waadRequestContent = new StringContent(postData, System.Text.Encoding.ASCII, "application/x-www-form-urlencoded");

  13:  

  14: string postUrl = string.Format("https://login.windows.net/{0}/oauth2/token?api-version=1.0", tenantId);

  15:  

  16: var waadResult = await waadRequest.PostAsync(postUrl, waadRequestContent);

  17:  

  18: waadResult.EnsureSuccessStatusCode();

  19:  

  20: var result = await waadResult.Content.ReadAsStringAsync();

  21:  

  22: var jObject = JObject.Parse(result);

  23: var accessToken = jObject.SelectToken("access_token");

  24:  

  25: var graph = new DirectoryGraph(tenantId, accessToken.Value<string>());

  26:  

  27: string nextPageUrl;

  28:  

  29: var user = graph.GetUsers(out nextPageUrl);

  30: ...

Ergebnis: Ein AccessToken mit dem man die User des Tenants abfragen kann.

Zusammengefasst:

Wir haben damit eine sehr simple Applikation geschrieben, über welche man sich am Azure AD anmelden kann und das Verzeichnis auch auslesen kann. Ohne den Config-Wizard zu benutzen.

image

Multitenancy?

Mit der Variante ist es nun sehr einfach eine Multimandanten-WAAD-Applikation zu schreiben. Was man dazu machen muss: Die “AzureAdAuthroAuthority” muss alle bekannte Tenants kennen. In meinem Beispiel ist dies nur statisch auf mein Demo Azure Tenant eingestellt, aber die Daten können auch aus einer Datenbank kommen. Wichtig ist hier noch, dass Azure AD generell dann nur mit HTTPS Urls umgehen kann. Der Redirect auf eine Non-HTTPS Url kann in bestimmten Situationen zu Fehlern führen (z.B. wenn ein Fremder Admin eurer App “Vertrauen” will).

Das Toolkit macht im Grunde nix anderes

Soweit ich das sehen konnte ist die Redirect-Geschichte fast identisch gemacht (nur gibt es dazu WSFed-Hilfklassen dazu). Der Callback wird über ein Modul gemacht – was unter umständen cleverer ist, aber mir zu magisch war.

Login mit Twitter oder Microsoft Account?


Ich habe bereits in der Vergangenheit zwei ähnliche Artikel geschrieben – wieder mit “Low-Level” Mitteln.

Authentifizierung mit Twitter

Authentifizierung mit Microsoft Account

Democode auf GitHub

Der Code vom Tool als auch von meiner “Basic”-Variante ist natürlich auf GitHub. Die Secrets müsstet ihr natürlich mit euren austauschen.

Read more

HttpClient, Twitter OAuth & die Twitter Timeline auslesen

image.png

Die Twitter Timeline eines Nutzers über die API auszulesen ist nicht ganz so trivial wie ein RSS Feed parsen. Größte Hürde ist, dass fast alle API Aufrufe bei Twitter eine Authentifizierung erfordern. Dabei kommt OAuth zum Einsatz, welches selbst nicht ganz so einfach zu verstehen ist. Aber der Reihe nach… Zusätzlich nutzen wir den “neuen” […]

Read more

Eigene Json-Web-Tokens (JWTs) erstellen und validieren

image.png

Wer sich mit Authentifizierung im Web befasst wird früher oder später auf den Begriff JSON Web Token treffen (JWT). Was ist ein JWT?Vermutlich nutze ich nicht die Security-Fach-Termini, aber seis drum: JWTs werden eingesetzt um Claims zwischen zwei Systemen auszutauschen. Beispiel: Über eine App möchte man sich an einem Dienst (Facebook, Twitter, etc.) einloggen und […]

Read more

Dateidownload über FTP am Beispiel von Azure Websites Diagnostics

Websites auf Azure legen Diagnoseinformationen (Fehler Berichte, IIS Logs, Git Logs oder eigene Logfiles) als Text-Datei auf dem Server ab. Diese lassen sich relativ einfach via FTP auslesen. Der FTP Endpunkt für eine Website in West-Europa sollte dieser sei: ftp://waws-prod-am2-001.ftp.azurewebsites.windows.net Zu sehen ist die natürlich auch im Azure Management:             […]

Read more

Unit Testing mit Entity Framework–über Effort

image.png

Das Entity Framework ist zwar nicht unumstritten, aber wird oftmals in Verbindung mit der Datenabfrage aus dem SQL Server eingesetzt. Solche Lösungen neigen allerdings oftmals dazu das Thema Unit-Testing zu vernachlässigen. Das Problem: Der SQL Server ist langsam und eine unangenehme Abhängigkeit bei Unit Tests Unit Tests – so steht es schon im Namen – […]

Read more

OWIN, WebAPI & RazorViewEngine

image_thumb.png

Die ersten Schritte mit OWIN sind recht schnell gemacht. In diesem Blogpost möchte ich über OWIN die WebAPI nutzen – allerdings nicht als REST Endpunkt, sondern um HTML zurückzugeben. Für alle die mit OWIN garnichts anfangen können, der könnte ein Blick auf meine Unterlagen werfen. Warum nicht ASP.NET MVC? Aktuell ist das MVC Framework sehr […]

Read more

Fix: CA0058 : The referenced assembly ‘System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ could not be found.

Ich hatte kürzlich mit FxCop bzw. der Code Analyse unter Visual Studio 2012 ein Problem. Eines der WebApi NuGet Packages enthielt die Assembly “System.Net.Http”, allerdings sprang hierauf die Code Analyse an: “CA0058 : The referenced assembly ‘System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ could not be found. This assembly is required for analysis and was referenced by: C:\…\bin\Web.dll, […]

Read more

Caller Information mit .NET 4.5 oder “Wer hat die Funktion aufgerufen?”

Debugging und Logging Code strotzt meist vor Funktionsnamen und co. – nur damit man am Ende im Log wieder die passende Stelle im Code findet. Natürlich gibt es noch weitere Gründe herauszufinden wer welchen Code aufgerufen hat. Das Interface INotifyPropertyChanged ist auch solch ein Beispiel. Hier wird der Name des Properties benötigt. Dies kann man […]

Read more

OWIN, Katana & One ASP.NET

Dies war das Thema bei der .NET User Group Zürich am letzten Mittwoch. Ich möchte hier meine Präsentationsunterlagen zur Verfügung stellen. Präsentation auf SpeakerDeck Link zur Präsentation. Demo Code Der gesamte Demo-Code ist auf GitHub zu finden. Weitere Links Eine gute Zusammenfassung des Katana/OWIN-Teils findet man auch als Video auf Channel 9 bzw. auf der […]

Read more

Interne Tools – billig und geschmacklos, richtig?

image.png

Es gibt ein tooles Sprichwort “Schuster haben die schlechtesten Schuhe” – sowas sieht man natürlich auch oft in der IT. Interne Tools oder Dienstleistungen zu eigenen, also internen, Zwecken werden meist halbherzig oder auch gar nicht mit der nötigen Professionalität betrieben und entwickelt. Die Grundidee – alles für den Kunden! Die Zeit die man fürs […]

Read more

Letzte Posts

  • image.png
    Azure AppInsights: Ein mini Google Analytics für Websites

    Seit der Build Konferenz ist das neue Azure Portal für alle freigeschaltet. Durch das neue Portal ist mir ein “Dienst” aufgefallen, den ich bisher nicht gesehen hatte: Azure Application Insights Viel weiss ich nicht über den Dienst, aber wer eine Azure Website hat der sollte mal die “Analytics” Box öffnen. Im Grunde handelt es sich […]

  • image.png
    Source Code veröffentlichen – aber bitte mit Lizenz

    Seit es den Blog gibt wird auch meist der gesamte Demo Source Code mit veröffentlicht. Das Ganze hatte ich am Anfang noch als .zip verteilt, später lag es mal auf Google Code und nun liegen alle Samples und sonstige Sachen auf GitHub. Beim letzten User Group Treffen in Zürich mit dem Titel “Open Source: Get […]

  • Fix: Cannot convert from ‘CConnectProxy::_ComMapClass *’ to ‘AddInDesignerObjects::IDTExtensibility2 *’

    Mal einen etwas esoterischer Blogpost, welcher auftaucht wenn man zu viel mit Office Addins rumspielt. Der Fehler passiert beim Bauen von C++ Projekten, welchen diesen Typ benötigen. Lösung (auf 64bit Systemen): C:\Program Files (x86)\Common Files\DESIGNER>regsvr32 MSADDNDR.DLL And Rebuild. Meine lieben Kollegen hatte mir dies schon mehrfach gesagt, allerdings hatte ich es immer wieder vergessen Das […]

  • Gegen das Gesetz verstoßen: X Jahre Haft. Gegen die Terms of Use verstoßen: Bann auf Lebenszeit. Danke Google & co.

    Bei fast allen Diensten die man im Internet nutzen kann muss man den “Terms of use” zustimmen. Völlig logisch dass da natürlich drin steht was erlaubt und was nicht. Wenn man gegen diese Regelungen verstößt hat das Unternehmen natürlich das Recht etwas dagegen zu unternehmen. In der heutigen Welt beherrschen einige wenige Unternehmen die digitale […]

  • image.png
    RSS Feed samt Kommentaranzahl und andere nicht Standard Elemente mit dem SyndicationFeed auslesen

    Jetzt mal ein Blogpost ohne ein fancy NuGet Package: Seit .NET 3.5 gibt es die SyndicationFeed Klasse. Eine schon etwas ältere API, reicht aber aus um Atom bzw. RSS Feeds zu lesen. In diversen RSS Feeds gibt es aber Erweiterungen, welche man natürlich auch auslesen möchte. So gibt WordPress z.B. auch die Anzahl der geposteten […]

Amazon Shop

Facebook