Im Augenblick entwickel ich eine Architektur für eine WEB-API basierend auf der WCF. Als Grundlage habe ich das WCF Http Projekt (das auf Codeplex zu finde ist) genommen. Mir gefällt dort insbesondere der Ansatz der MediaTypeProcessor, womit sich die Request- und Response-Formate sehr schön beeinflussen lassen. Ein wichtier Aspekt bei jeder Architektur ist das Thema Exceptionhandling. Leider gibt es für das oben genannte Projekt noch keinen eigenen Exceptionhandler, der auch die MediaTypeProcessors nutzt, um eine Exception im angeforderten Format zurück zu geben. Das kann z.B. XML, Json aber theoretisch auch ein Bild oder Wav Dateien sein. Daher habe ich heute mal einen Exceptionhandler geschrieben, der mit dem Projekt zusammenarbeitet. Als Basis wird hierbei natürlich das Interface der WCF IErrorHandler genutzt und eine generelle Basisimplementierung aus dem Projekt. Ich bin noch nicht 100% glücklich mit der Lösung aber im Augenblick funktioniert das so ganz gut. Werde die Implementierung auch auf Codeplex posten und hoffe dort vielleicht weitern Input zu finden. Aber auch per E-Mail freue ich mich über konstruktive Beiträge! Here we go: public class RESTMessageErrorHandler : HttpMessageErrorHandler, IErrorHandler
{
// Public Methods
#region HandleError
public override bool HandleError(
Exception error)
{
Logging.Error("API Exception", error);
return true;
}
#endregion
// Protected Methods
#region ProvideResponse
protected override void ProvideResponse(
Exception exception,
Microsoft.Http.HttpResponseMessage response)
{
APIBaseException apiException = null;
if (exception is APIBaseException)
apiException = exception as APIBaseException;
else
apiException = new APIBaseException(System.Net.HttpStatusCode.InternalServerError, "An error has occured processing your request.");
var supportedMediaTypes = new List<string>();
var httpMessageProperty = OperationContext.Current. IncomingMessageProperties[HttpMessageProperty.Name] as HttpMessageProperty;
var httpRequest = httpMessageProperty.Request as HttpRequestMessage;
var contentType = httpRequest.Headers.ContentType;
var uriMatch = httpRequest.Properties.First( p => p.GetType() == typeof(UriTemplateMatch)) as UriTemplateMatch;
var endpoint = OperationContext.Current.Host.Description.Endpoints.Find( OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
var dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime. Operations.Where(op => op.Name == uriMatch.Data).First();
var operationDescription = endpoint.Contract.Operations.Find(dispatchOperation.Name);
//get the contenttype of the request
var httpBehavoir = endpoint.Behaviors.Find<HttpEndpointBehavior>();
var processors = httpBehavoir.GetResponseProcessors( operationDescription.ToHttpOperationDescription()).ToList<Processor>();
//Fallback for empty contenttype
if (string.IsNullOrEmpty(contentType))
{
foreach (var processor in processors)
{
var mediaTypeProcessor = processor as MediaTypeProcessor;
if (mediaTypeProcessor == null)
continue;
supportedMediaTypes.AddRange(mediaTypeProcessor.SupportedMediaTypes);
}
contentType = ContentNegotiationHelper.GetBestMatch(httpRequest.Headers.Accept.ToString(), supportedMediaTypes).MediaType;
if (string.IsNullOrEmpty(contentType))
contentType = "text/plain";
}
//set http-header and status code
response.Headers.ContentType = contentType;
response.StatusCode = apiException.Status;
//search processor for the output-serialization
foreach (var processor in processors)
{
var mediaTypeProcessor = processor as MediaTypeProcessor;
if (mediaTypeProcessor == null)
continue;
if (mediaTypeProcessor.SupportedMediaTypes.Contains<string>(contentType))
{
response.Content = HttpContent.Create(s => mediaTypeProcessor. WriteToStream(new APIExceptionContract(apiException), s, httpRequest));
break;
}
}
//if no processor found use plain text
if (response.Content == null)
response.Content = HttpContent.Create(apiException.Description);
}
#endregion
}
Bei der Umstellung eines ASP.NET Projektes auf das Framework 4.0 wurde bei bestimmten Eingabedaten immer der Fehler geworfen: System.Web. HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (_dataTextBox="...bitkarte (<print template="pay..."). at System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) at System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) at System.Web.HttpRequest.get_Form() Dieses konnte man unter ASP.NET 2.0 durch ein @pagedirektive unterdrücken bzw. die Filterung ausschalten. Bei ASP.NET 4.0 ist dieses per @pagedirektive aber nicht mehr per Default möglich, es gibt aber die Möglichkeit die RequestValidierung per Eintrag in die web.config wieder in den Modus "ASP.NET 2.0" zu versetzen, damit das Verhalten gleich bleibt. Dafür ergänzt man die web.config wie folgt: <httpRuntime requestValidationMode="2.0" /> Weiter Informationen gibt es in der MSDN.
Bei dem IIS 7.5 hatte ich gerade das Problem, dass eine Url die Whitespaces als " +" codiert (auch wenn es nicht optimal ist aber leider nicht zu ändern aktuell) immer mit dem Fehler http Statuscode 404.11 und der Nachricht The request filtering module is configured to deny a request that contains a double escape sequence. beendet wurde. Der Grund für die Ablenung der Url ist, dass "+" als ein gefährliches Zeichen eingestuft wird. Hierbei handelt es sich also um eine Sicherheitseinstellung. Wenn man nun solche Urls aber weiter verarbeiten möchte, dann kann man diesen Requestfilter einfach deaktivieren über folgenden Aufruf: %windir%System32\inetsrv>appcmd set config -section:system.webServer/security/requestfiltering -allowDoubleEscaping:trueWeitere Informationen zum RequestFiltering gibt es auch hier IIS Security RequestFiltering.
In einer Evaluierungsphase habe ich gerade mal probiert eine alte ASP.Net 1.1 Anwendung auf einem Windows Server 2008 zu installieren. Per Default wird allerdings ASP.NET 1.1 nicht mehr auf einem Windows 2008 Server unterstützt, so das ein wenig manuelle Arbeit notwendig ist. Als erstes muss man die " IIS Metabase Compatibility" installieren und das geht durch die Schritte: "Start" -> "Server Manager" -> "Manage Roles" -> "Web Server (IIS)" -> "Add Role Services". Der zweite Schritt ist die Installation vom .Net Framework 1.1. Hier die Downloadlinks: .NET Framework Version 1.1 Redistributable Package.NET Framework Version 1.1 Service Pack 1ASP.NET Security Update for .NET Framework 1.1 SP1Wenn man das Setup ausführt, dann bekommt man vom Windows Server 2008 den Hinweis das es möglicherweise Kompatibilitätsprobleme geben könnte. Diese Meldung einfach mit "Ausführen" / "run programm" überspringen. Anschließend muss das alte .Net Framework noch im IIS registriert werden. Dafür kann man folgenden Behfel ausführen: %windir%\Microsoft.NET\Framework\v1.1.4322\aspnet_regiis -enableEin Änderung in der machine.config (unter %windir%\Microsoft.NET\Framework\v1.1.4322\config\machine.config) muss noch gemacht werden. Vor dem schließenden Tag </configSection> muss folgendes hinzhugefügt werden: <section name="system.webServer" type="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> Einen neue ApplicationPool - der unter .Net 1.1 läuft - kann man nun mit folgendem Befehl anlegen: %windir%\system32\inetsrv\appcmd add apppool /name:"Pool1-1" /managedRuntimeVersion:"v1.1" Bei einem 64bit Betriebsystem muss man nun noch ein Verzeichnis erstellen: md %windir%\Microsoft.net\Framework64\v1.1.4322\config und copy %windir%\Microsoft.net\Framework\v1.1.4322\Config\machine.config %windir%\Microsoft.net\Framework64\v1.1.4322\config\machine.config
Heute habe ich versucht bei mir lokal ein SSL Zertifikat zu installieren. So etwas habe ich nicht zum ersten mal gemacht aber heute wollte es einfach nicht funktionieren. Immer wenn ich den IIS entsprechend konfiguriert hatte (Zertifikat importiert, Binding bzw. Hostheader erstellt, etc.) kam beim Versuch den IIS zu starten immer die Meldung: IIS Manager Error: The process cannot access the file because it is being used by another process. (Exception from HRESULT: 0×80070020)
Nach der Analyse habe ich dann festgestellt, dass ein Prozess bereits den Port 443 nutzt und daher der IIS mit einem https-Binding natürlich nicht mehr richtig starten konnte. Herausfinden welcher Port aktuell genutzt wird kann man im übrigen über "netstart -ano" im Cmd-Prompt. Der Befehl "Tasklist" hat mir dann den notwendigen Hinweis gegeben. Skype ist der "Bösewicht" der den Port 443 nutzt. Dieses kann man aber per Konfiguration ausschalten. Danach funktioniert auch der Start vom IIS mit einem htts-Binding
Bei dem Standardverhalten, wenn ein WCF Service über den IIS veröffentlicht wird ist, dass der Endpunkt die Datei von Service ist mit der Dateiendung " .svc". Dieses sieht aber - gerade im Bezug auf ein REST-basiertes System nicht besonders elegant aus. Bei dem Einsatz von IIS 7.0 ist es sehr einfach die Dateiendung zu entfernen, ohne dabei viel Code zu schreiben. Für das URL Rewriting gibt eine Erweiterung, die man dem IIS 7.0 hinzufügen kann. Dadurch ist es sehr schön möglich z.B. über Regular Expressions ein URL Rewriting durchzuführen. Nach der Installation dieser Erweiterung muss nur noch folgende Regel definiert werden: 1. Name: Entfernen der Dateiendung svc2. Request URL: Matches the pattern3. Using: Regular Expressions4. Pattern: ^([0-9a-zA-Z\-]+)/([0-9a-zA-Z\-\.\/\(\)]+) 5. Ignore Cases: true6. Action Type: Rewrite7. Rewrite URL: {R:1}.svc/{R:2}8. Append Querystring: trueFertig  Per Eintrag in der web.config sieht das dann alternativ so aus: <system.webServer> <modules runAllManagedModulesForAllRequests="true" /> <rewrite> <rules> <rule name="Remove Svc Extension"> <match url="^([0-9a-zA-Z\-]+)/([0-9a-zA-Z\-\.\/\(\)]+)" /> <action type="Rewrite" url="{R:1}.svc/{R:2}" /> </rule> </rules> </rewrite> </system.webServer>
Jeder Webservice sollte einen eindeutigen Namespace verwenden, um im Web auf jeden Fall eindeutig zu sein. Als Standardnamespace wird von ASP.NET Webservices (und auch von der WCF) folgender Namespace verwendet: http://tempuri.orgDieses sollte als erstes modifiziert werden, damit man erst gar nicht mit einem solchen Namespace online geht. Das Problem bei der WCF ist nun leider, dass der Namespace an drei verschiedenen Stellen angegeben werden muss, damit auch im WSDL der gewünschte Namespace durchgängig verwendet wird. Als erstes muss man dem Namespace beim der Servicebeschreibung dem [ ServiceContract] angeben:
[ServiceContract(Namespace = "http://dotnetnukeblog.de")]
public interface IPostServiceDie zweite Stelle ist bei der Serviceimplementierung:
[ServiceBehavior(Namespace = "http://dotnetnukeblog.de")]
class PostService : IPostService
Die letzte Stelle ist bei der Konfiguration des Endpoints mit dem Attribute bindingNamespace: <endpoint binding="basicHttpBinding" bindingNamespace="http://dotnetnukeblog.de".... Erst wenn an allen drei Stellen der Namespace gesetzt wurde, wird dieser auch durchgängig bei der WSDL Erzeugung genutzt.
Nachdem ich an einem jungfräulichen Rechner sitze und gerade einen WCF Service debuggen wolte, bekam ich ständig vom IIS den Fehlercode 404.3. Schnell habe ich herausgefunden das die verwendete Endung " .svc" nicht einem Handler zugeordnet ist. Um dieses aber nicht manuel machen zu müssen gibt es bei der WCF ein Tool, dass die Registrierung übernimmt. Das Tool findet man unter %Windows%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\ und heißt ServiceModelReg.exe. Das muss mit dem Parameter "-i" aufgerufen werden und anschließend funktioniert auch das Hosting im IIS.
Es gibt immer wieder mal Fälle, wo man sich gerne den von ASP.NET erzeugten Viewstate anschauen möchte, um zu sehen, welche Kompontenten dort etwas reinschreiben, zur Optimierung, etc. Für das Pflichttool (zumindest für Webentwickler) Fiddler gibt es genau für diese Aufgabe eine sehr schöne Erweiterung: Den ASP.NET ViewState Helper Damit kann man sich den decodierten Viewstate innerhalb vom Fiddler anschauen und sehr schön erkennen, was dort zum Client übertragen wurde. Diese Erweiterung ist kostefrei und sehr einfach zu installieren. Dafür muss man lediglich die Software runterladen und anschließend die Datei in das Unterverzeichnis "Inspectors" kopieren. Schon hat man nach dem nächsten Start von Fiddler einen neuen Tab-Reiter mit dem decodierten Viewstate.
Beim Testen eines Redesign hatte ich das Problem das die neue Seite in
allen Browsern angezeigt wurde, nur nicht im Internet-Explorer (auf
jeden Fall im IE 7 und 8). Im IE sah ich eine leere Seite / blank page. Durch den Einsatz vom vom HTTP Debugging Tool Fiddler konnte ich aber sehen das der komplette Inhalt zum Browser übertragen wurde, habe ich mir den Quellcode anzeigen lassen, war auch alles in Ordnung. Allerdings zeigten mir die Entwicklertools - genau wie der Browser selber - auch kein Ergebnis an. Nachdem ich mir dann den Quellcode etwas näher angeschaut habe, musste ich festestellen, dass der Code unsauber war. Im Head-Bereich habe ich das Standard-Tag title verwendet aber leider sah das so aus: <title>Meine tolle Seite<title> Das Tag wurde leider nicht geschlossen. Das scheint dem IE überhaupt nicht zu schmecken und verursacht, dass die Seite komplett nicht angezeigt wird. Nachdem ich den Fehler behoben habe und das title-Tag ordnungsgemäß geschlossen hatte, wurde auch die Seite endlich im IE angezeigt.
Beschäftige mich aktuell intensiver mit dem System Umbraco. Dabei versuch ich einen Datentyp für die Administration zu entwicklen, der per AJAX Daten aus einer Datenbank lädt. Ein Datentyp in Umbraco ist z.B. ein Textfeld, Checkbox oder ähnliches um im Adminbereich das System mit Inhalten zu befüllen. Bei meiner Suche bin ich dann auf ein jQuery-Plugin namens autocomplete aufmerksam geworden. Damit kann man eine Textbox via JavaScript mit einer autocomplete-Funktion erweitern. Da ich die Daten aber nicht per JSON direkt mit zum Client übertragen wollte, habe ich dafür einen asmx-Webservice geschrieben. Die Einbindung via jQuery ist denkbar einfach und sieht in C# z.B. so aus: private void _BuildAutoCompletedScript()
{
StringBuilder clientScript = new StringBuilder();
clientScript.Append(" <script type='text/javascript'>");
clientScript.Append(" $(document).ready(function() { ");
clientScript.AppendFormat(" $(\"#{0}\").autocomplete( ", this.autoCompleteTextbox.ClientID);
clientScript.Append(" \"/umbraco/webservices/api/mywebserive.asmx/mymethod\", ");
clientScript.Append(" { delay:10, minChars:2, matchContains:1, cacheLength:10, autoFill:true } ");
clientScript.Append(" ); ");
clientScript.Append(" }); ");
clientScript.Append(" </script>");
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), this.ClientID + "_autocompleteData", clientScript.ToString());
this.Page.ClientScript.RegisterClientScriptInclude("jquery.autocomplete", "/umbraco_client/Application/JQuery/jquery.autocomplete.js");Auf der Serverseite wird dann eine Web-Servicemethode definiert: [WebService(Namespace = "uri:umbraco-irgendwas")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class mywebservice : System.Web.Services.WebService
{
[WebMethod]
public string mymethod(string q, int limit)
{
return "Hello World" + q;
}
}Die Parameter q und limit wird vom Plugin automatisch beim Aufruf als Parameter übergeben. Dabei ist q der Inhalt aus dem Textfeld und limit ist die maximale Anzahl an Datensätzen, die zurück geliefert werden sollen. So weit so einfach, doch leider habe ich beim Aufruf immer einen http-Fehlercode 500 bekommen. Die Lösung habe ich noch einiger Recherche dann gefunden. Die web.config muss um folgendes ergänzt werden: <webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
<add name="HttpSoap"/>
</protocols>
</webServices> sonst kann der Web-Service nicht via GET aufgerufen werden.
Auch wenn der FCKEditor mittlerweile vielfach durch den CKEditor ersetzt wird, wird in älteren Projekten dieser immer noch eingesetzt. Vielfach gibt es den Wunsch das man beim Schreiben von Texten die Anzahl der Zeichen sieht, damit man z.B. in Teaserboxen nicht zu viel Inhalt unterbringt. Vor einiger Zeit habe ich ein Plugin für den FCKEditor gefunden der so etwas ähnliches macht. Das Plugin zählte die Zeichen und nach einem eingestellten Maximalwert, wird die Eingabe verweigert. Für meine gewünschten Fall war das aber zu viel, da lediglich die Anzahl der Zeichen angezeigt werden sollen. Da es auch noch ein paar Probleme mit dem Plugin gab, habe ich mich heute hingesetzt und dieses etwas umgeschrieben. Den Download gibt es am Ende des Beitrages. Die Einbindung ist sehr simple: Den Ordern als Unterordner von Verzeichnis plugins kopieren. Den Ordner Plugin findet man bei DotNetnuke normlerweise unter ({webroot}\Providers\HtmlEditorProviders\Fck\FCKeditor\editor\plugins\) Dann muss man die Konfigurationsdatei vom Editor anpassen und folgende Zeile hinzufügen: FCKConfig.Plugins.Add( 'CharsCounter', '' ) ;Ebenfalls in der Konfiguraationsdatei muss dann ein Button bzw. eine "Toolbar" hinzugefügt werden. Das ist sehr einfach und man muss lediglich das entsprechende Toolbarset erweitern um den Eintrag CharsCounter. Hier ein Beispiel: FCKConfig.ToolbarSets["Basic"] = [
['Bold','Italic','-','OrderedList','UnorderedList','-','Link','Unlink','-','About'], ['CharsCounter']
] ;
Die Konfigurationsdatei vom Editor befindet sich unter {webroot}Providers\HtmlEditorProviders\Fck\Custom. Dann wird in der Toolbar vom Editor die Anzahl der Zeichen angezeigt.  Den benötigte JavaScript-Code gibt es hier als Download: FCKEditor_CharsCounter_Plugin.zip (1,81 KB)
Auf der Suche nach einer guten Lösung um E-Mails via Template versenden zu können habe ich heute ein interessantes Open-Source Projekt gefunden. Town Crier ist eine smarte Lösung, um nicht selber ständig so etwas per "string.replace" machen zu müssen - bzw. sich selber mit dem Gedanken auseinander setzen zu müssen eine Template-Engine in .NET zu entwicklen. Den .NET Source-Code für dieses Projekt kann hier im GitHub-Repository runterladen! Entwickelt wurde die Engine in C# und steht unte der "Lesser GNU Public Licence". Eine kurze Einführung findet man hier.
Bei einem Ur-Alt Portal (DotNetNuke 3.2.2) das noch hobbymäßig betreut habe, steht nun der Wechsel zu einer anderen Plattform an. Da der Benutzer aber kein neues Passwort bekommen sollten, müssen die existierenden Passwörter aus DNN exportiert werden. Die Passwörter wurden über das ASP.NET Membership Model verwaltet und die Passwörter sind nicht als Klartext sondern verschlüsselt in der Datenbank vorhanden. Ein simpler Export der Daten nutzt also an dieser Stelle nichts. Daher habe ich mich heute Abend hingesetzt und eine Quick and Dirty-Lösung entickelt, die es erlaubt einen Webservice aufzurufen, der dann wiederum eine CSV-Datei auf dem Server erstellt. Warum dann einen Webservice? Nun, zunächst hatte ich mir das etwas anderes gedacht - bin dann aber aus lauter Faulheit dazu übergegangen die Daten direkt lokal zu speichen. Von Quellcode her nicht wirklich optimal und wohl alles andere als CCD-konform .. aber es funktionierte für meinen einmaligen Zweck. Sollte das noch öferts anstehen, muss man über eine allgemeingültigere Lösung nachdenken und auch die Export-Funktion anpassen. Obwohl der Code nicht gerade ne Refernz ist, möchte ich diesen veröffentlichen und vielleicht hilft es ja dem einen odere anderen ebefalls die Passwörter seiner DotNetNuke User zu entschlüsseln. An alle Kritiker des Datenschutzes: Ja das habe ich auch anbemängelt, allerdings wollte das mein Gegenüber so habe. Bitteschön UserWebService.zip (7,65 KB)
Im Breadcrumb Skinobject von DotNetNuke wird per Default immer der Seitenname angezeigt. Es kann aber durchaus Fälle geben, bei denen es sinnvoll ist nicht den Seitennamen sondern den Seitentitel anzeigen zu lassen. Der Seitennamen ist die Bezeichnung im Menü und der Seitentitel ist der Browsertitel. Wenn man nun anstelle vom Seitenamen den Seitentitel nutzen möchte, dann kann man dieses per Konfiguration der Komponente ganz einfach erreichen. Hier gibt es die Eigenschaft "UseTitle" und wenn diese mit dem Wert "true" belegt wird, beeinflusst das die Darstellung. Hier als Beispiel: <dnn:BREADCRUMB runat="server" id="dnnBREADCRUMB"
CssClass="Breadcrumb" RootLevel="0"
Separator=" > " UseTitle="True" />
Das Socialmedia Publisher Projekt wurde in der zwischenzeit um eine Anbindung an einen URL Shorter Dienst erweitert. Damit man für die unterschiedlichen Socialmedia Plattformen (Twitter, Facebook, etc.) möglichst flexible bleibt, wurde bei der Implementierung das auch in DotNetNuke sehr oft verwendete Provider Pattern verwendet. Der Vorteil dabei ist, dass erst zur Ausführungszeit entschieden wird, welche konkrete Implementierung verwendet wird. Somit ist es also möglich für Facebook z.B. TinyURL zu verwenden und bei Twitter bit.ly. Die dafür benötigte abstracte Klasse sieht so aus: public abstract class URLShorterProvider
{
#region [ Shared/Static Methods ]
private static URLShorterProvider _urlShorterProvider = null;
public static URLShorterProvider Instance(string typeName)
{
URLShorterProvider urlShorterProvider = null;
CacheManager uscProviderCache = null;
try
{
uscProviderCache = CacheFactory.GetCacheManager ("URLShorterProviderCache");
}
catch
{ }
if (uscProviderCache != null)
urlShorterProvider = (URLShorterProvider)uscProviderCache .GetData ("USC" + typeName);
if (urlShorterProvider == null)
{
urlShorterProvider = (URLShorterProvider)TC.Framework. ProviderPattern.ProviderBase.InitInstance(typeName);
if (uscProviderCache != null)
uscProviderCache.Add("USC" + typeName, urlShorterProvider, CacheItemPriority.High, null, new NeverExpired());
}
return urlShorterProvider;
}
#endregion
#region [ abstract methods ]
public abstract string ShortUrl(string url);
#endregion }
Genutzt wird hier das singelton Pattern in Kombination mit einem Caching. Die eigentliche Implementierung für TinyURL ist sehr einfach gehalten und sieht wie folgt aus: public class TinyURL : URLShorterProvider
{
///Die maximale Länge der URL, bevor diese gekürtzt wird.
private const int MAX_URL_LENGTH = 26;
public override string ShortUrl(string url)
{
try
{
if (url.Length < MAX_URL_LENGTH)
return url;
return new System.Net.WebClient().DownloadString ("http://tinyurl.com/api-create.php?url=" + System.Web.HttpUtility.UrlEncode(url));
}
catch(Exception exc)
{
Diagnostics.ExceptionHelper.HandleException(exc);
return "";
}
}
}Mit dieser Methode kann man nun sehr einfach und ohne großen Aufwand neue URLShoter-Dienste anbinden und per Konfiguration diese Dienste dann zuordnen.
Das bisher in der DotNetNuke Professional verfügbare RibbonBar Control Panel - eine Alternative zu dem normalen ControlPanel - steht jetzt auch für die Community Version zur Verfügung. Im Vergleich zu dem normalen Control Panel, hat der Bearbeiter hier deutlich mehr Möglichkeiten die wichtigen Parameter direkt zu beinflussen. Das RibbonBar Control Panel ist aufgeteilt in für Tabs / Bereiche: - Common Tasks
- Current Page
- Admin
- Host
Der Bereich Commen Tasks ist relativ identisch zu den bisher eingesetzten Control Panel. Zumindest auf den ersten Blick. Hier sind aber auch einige wirklich sinnvolle Erneuerungen aufgenommen. Bei der Neuanlage einer Seite kann man jetzt hier direkt die Informationen Name, Position in der Sitemap, Template, etc. definieren. Das kopieren von bereits existierenden Modulen von anderen Seiten wurde angepasst und kann man nicht nur eine Referenz von einem Modul nutzen, sondern auch ein komplett neues Modul mit den identischen Inhalten und Einstellungen erzeugen - also ein wirklicher 1:1 Kopiervorgang von einem bestehenden Modul. Der Bereich "Current Page" ist neu und bietet die Möglichkeit wichtige Parameter wie Name, Position in der Sitemap oder das vererben von Rechten direkt durchzuführen. Die beiden Bereiche Admin und Host zeigen die Punkte aus dem Administrationmenü an. Das finde ich ganz praktisch, das es immer wieder mal Unterseiten gibt, die über kein Hauptmenü verfügen und somit war man nie in der Lage direkt in einen Bereich von Admin oder Host zu gelangen.
Bei Anwendern die mit einer aktuellen Version vom Firefox 3.6 DotNetNuke administrieren möchten, haben ein Problem an das Kontext-Menü eines Modul zu kommen, da dieses einfach nicht sichtbar ist bzw. nicht angezeigt wird. Um dieses Problem zu beheben muss man in der JavaScript-Datei vom Solpartmenu eine Zeile verändern und dort den z-Index erhöhen. Die entsprechende JavaScriptdatei für das Menü befindet sich vom DotNetNuke-Root aus im Verzeichnis "/controls/SolpartMenu/spmenu.js". In der Zeile 948 befindet sich ein Eintrag: eMenu.style.zIndex = 1 Die Wert von 1 einfach erhöhren z.B. 10000 und anschliesend wird das Kontext-Menü von den DotNetNuke Modulen auch wieder im Firefox angezeigt.
Gerade habe ich ein wirklich praktisches kleines Tool gefunden, dass jeder der Subversion verwendet sich bestimmt schon mal gewünscht hat. Schon mehrfach hatte ich das Bedürfnis, die Arbeitskopie eines SVN-Projektes komplett und mit einem Klick von den SVN-Verwaltungsdateien zu befreien. Natürlich geht das auch über die Windowssuche, ein Kontextmenü im Explorer ist aber dafür deutlich besser geeignet. Daher meine Empfehlung: SVN-Cleaner. Die Webseite mit Informationen und dem Download findet man bei Google Project Hosting unter der URL http://code.google.com/p/svn-cleaner/.
In einem vorherigen Blogpost habe ich über meine Pläne eines Social Networks Publishing-Dienst berichtet. Mittlerweile haben diese Pläne bereits ganz konkrete Formen angemonnen. Eine Herausforderung an dem ganzen Dienst war es, die Aufbereitung der Nachrichten für die einzelnen Dienste wie Twitter, Facebook, etc. Jedes Netzwerk hat andere Möglichkeiten und ich wollte nicht das mögliche Beschränkung" eines einzelnen Social Network alle weiteren in Ihren Möglichkeiten beschränken. Damit man möglichst den vollen Umfang einer Plattform nutzen kann ist es also erforderlich, die jeweiligen Parameter konfigurierbar zu gestalten. Der Ablauf ist nun wie folgt: Es gibt eine zentrale Schnittstelle die z.B. eine Nachricht in der gesamten Länge aufnimmt. Bei der Übergabe wird gleichzeitig definiert für welche Social Plattformen die Nachricht bestimmt ist. Nun wird für jede Plattform die entsprechenden Einstellungen / Konfigurationen geladen, um anschließend die Nachricht für jede Plattform individuell aufzubereiten. Die "fertige" Nachricht wird in einer Datenbank gespeichert und zur Veröffentlichung frei gegeben. Das bedeutet natürlich das die eingehende Nachricht für jede anzusprechende Plattform einen eigenen Eintrag bekommt. Diese Redundanz ermöglicht es eine individuelle und optimierte Nachricht zur Verfügung zu stellen. Nebenbei läßt sich darüber auch eine zeitgesteuertes Veröffentlichung je Plattform realisieren. Die Anbindung eines URL-Shorter für die Links wird der nächste Schritte bei der Implementierung.
|